Spring IoC与AOP核心原理及面试高频题解析
1. Spring面试高频题解析IoC核心原理与实现Spring框架的IoC控制反转容器是其最核心的特性之一。传统编程中我们需要手动创建对象new操作而Spring IoC容器则负责对象的创建和依赖管理。让我们深入分析其实现原理。1.1 IoC容器的三级缓存机制Spring通过三级缓存解决循环依赖问题singletonObjects存放完全初始化好的单例BeanearlySingletonObjects存放早期暴露的Bean已实例化但未完成依赖注入singletonFactories存放Bean工厂对象// 简化版三级缓存实现 public class DefaultSingletonBeanRegistry { private final MapString, Object singletonObjects new ConcurrentHashMap(256); private final MapString, Object earlySingletonObjects new HashMap(16); private final MapString, ObjectFactory? singletonFactories new HashMap(16); public Object getSingleton(String beanName) { Object singletonObject this.singletonObjects.get(beanName); if (singletonObject null) { singletonObject this.earlySingletonObjects.get(beanName); if (singletonObject null) { ObjectFactory? singletonFactory this.singletonFactories.get(beanName); if (singletonFactory ! null) { singletonObject singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } return singletonObject; } }1.2 自定义简易IoC容器实现理解IoC原理最好的方式就是自己实现一个简易版本// 定义核心注解 Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) public interface Component {} Target(ElementType.FIELD) Retention(RetentionPolicy.RUNTIME) public interface Autowired {} // 简易IoC容器 public class SimpleIoC { private MapClass?, Object beans new HashMap(); public void registerBean(Class? clazz) { try { Object instance clazz.getDeclaredConstructor().newInstance(); beans.put(clazz, instance); } catch (Exception e) { throw new RuntimeException(创建Bean失败: clazz.getName(), e); } } public T T getBean(ClassT clazz) { return (T) beans.get(clazz); } public void inject() { for (Object bean : beans.values()) { Field[] fields bean.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); Object dependency getBean(field.getType()); field.set(bean, dependency); } } } } }1.3 BeanFactory与ApplicationContext区别特性BeanFactoryApplicationContext加载方式懒加载预加载功能范围基础IoC功能完整企业级功能AOP、事件等性能特点启动快运行期慢启动慢运行期快使用场景资源受限环境大多数应用场景2. AOP深度解析与实现原理2.1 AOP核心概念图解切面(Aspect) ├── 切入点(Pointcut) - 定义在何处执行 └── 通知(Advice) - 定义何时执行什么 ├── Before ├── After ├── AfterReturning ├── AfterThrowing └── Around2.2 动态代理实现方式对比2.2.1 JDK动态代理示例public class JdkProxyDemo { public static void main(String[] args) { UserService target new UserServiceImpl(); UserService proxy (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxyObj, method, args1) - { System.out.println([JDK代理]方法前增强); Object result method.invoke(target, args1); System.out.println([JDK代理]方法后增强); return result; } ); proxy.saveUser(test); } }2.2.2 CGLIB动态代理示例public class CglibProxyDemo { public static void main(String[] args) { Enhancer enhancer new Enhancer(); enhancer.setSuperclass(UserController.class); enhancer.setCallback(new MethodInterceptor() { Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println([CGLIB]方法前增强); Object result proxy.invokeSuper(obj, args); System.out.println([CGLIB]方法后增强); return result; } }); UserController proxy (UserController) enhancer.create(); proxy.getUser(1L); } }2.3 AOP织入时机对比表织入方式实现机制性能灵活性Spring支持编译期织入修改字节码最高最低有限支持类加载期织入通过ClassLoader修改高中需要配置运行时织入动态代理中最高默认支持3. 高频面试题深度解析3.1 Bean生命周期关键阶段实例化Instantiation属性填充Population初始化InitializationPostConstructInitializingBeaninit-method使用中In Use销毁DestructionPreDestroyDisposableBeandestroy-method3.2 循环依赖解决方案Spring通过三级缓存解决setter注入的循环依赖A实例化 - 放入三级缓存A属性注入时需要B - B开始实例化B实例化 - 放入三级缓存B属性注入时需要A - 从三级缓存获取A的早期引用B初始化完成 - A完成属性注入A初始化完成注意构造器注入的循环依赖无法解决会直接抛出BeanCurrentlyInCreationException4. 实战避坑指南4.1 常见问题排查表问题现象可能原因解决方案Bean注入失败未扫描到包检查ComponentScan配置事务不生效代理失效检查方法是否为publicAOP增强未执行切入点表达式不匹配调试Pointcut匹配逻辑循环依赖报错构造器注入循环改为setter注入4.2 性能优化建议合理使用Lazy延迟初始化避免过度使用AOP每个代理调用会有约20%性能损耗对于频繁调用的方法考虑使用AspectJ编译期织入谨慎使用Around避免不必要的proceed()调用5. 源码分析技巧5.1 关键源码位置IoC核心流程AbstractApplicationContext#refresh()DefaultListableBeanFactory#preInstantiateSingletons()AOP代理创建AbstractAutoProxyCreator#postProcessAfterInitialization()DefaultAopProxyFactory#createAopProxy()5.2 调试技巧在BeanDefinitionRegistryPostProcessor中打断点观察Bean定义使用条件断点过滤特定Bean的创建过程关注AbstractAutowireCapableBeanFactory#doCreateBean()方法在面试中当被问到Spring原理时建议从实际场景出发在我们项目中遇到XX问题时通过分析Spring源码发现...这样的回答方式更能体现你的实战能力。记住面试官更关注你如何运用原理解决实际问题而非单纯背诵实现细节。