Spring IOC控制反转底层原理详解Spring 的核心是 IoCInversion of Control控制反转容器它将对象的创建、装配、管理交给 Spring 框架从而降低组件之间的耦合度。理解其底层原理需要从IoC 思想、Bean 定义与注册、依赖注入机制、Bean 生命周期、循环依赖解决等多个维度深入剖析。一、IoC 与 DI 的本质控制反转传统程序中对象由使用者主动new创建依赖关系硬编码在代码中。IoC 将控制权转移到容器容器负责创建和管理对象应用程序只需声明“我需要什么”。依赖注入DI容器在创建对象时动态地将它所依赖的其他对象通过构造器、Setter 或字段注入进去。这是 IoC 的具体实现方式。Spring 的 IoC 容器通过反射和工厂模式实现对象的动态创建与装配。二、Spring IoC 容器的核心组件组件作用BeanDefinition存储 Bean 的元信息类名、作用域、依赖、初始化方法等BeanDefinitionRegistry注册表保存所有BeanDefinitionBeanFactory最底层的 IoC 容器提供 Bean 的获取、判断类型等基础功能ApplicationContext继承BeanFactory增加国际化、事件传播、AOP 等企业级功能BeanPostProcessorBean 的后置处理器允许在 Bean 初始化前后进行增强InstantiationStrategy实例化策略默认使用 CGLIB 或 JDK 反射创建对象三、IoC 容器启动过程核心流程以典型的AnnotationConfigApplicationContext为例启动代码如下ApplicationContextctxnewAnnotationConfigApplicationContext(AppConfig.class);MyServiceservicectx.getBean(MyService.class);启动过程分为三个阶段配置解析 → Bean 定义注册 → Bean 实例化与初始化。1. 配置解析与 BeanDefinition 生成根据传入的配置类ConfigurationSpring 使用ClassPathBeanDefinitionScanner扫描指定包下的Component、Service、Repository等注解。对于每个被标注的类创建一个BeanDefinition对象通常为ScannedGenericBeanDefinition记录Bean 的类全名作用域默认singleton构造器参数依赖属性依赖Autowired标记的字段/方法初始化方法、销毁方法等如果存在Bean方法则生成ConfigurationClassBeanDefinition存储工厂方法和参数信息。生成的BeanDefinition会通过BeanDefinitionRegistry注册到容器本质是一个ConcurrentHashMap。2. Bean 实例化与初始化核心步骤当调用ctx.getBean()或容器预加载单例 Bean默认非懒加载时触发实例化过程步骤概览实例化对象通过反射或 CGLIB 创建原始对象填充属性执行依赖注入BeanNameAware / BeanClassLoaderAware 回调BeanPostProcessor.postProcessBeforeInitializationPostConstruct / afterPropertiesSet / init-methodBeanPostProcessor.postProcessAfterInitialization注册销毁回调单例 Bean详细底层实现实例化通过InstantiationStrategy的策略模式默认使用SimpleInstantiationStrategy利用Constructor.newInstance()或 CGLIB 动态创建字节码对象针对没有无参构造且被代理的场景。依赖注入遍历BeanDefinition中的依赖信息如Autowired字段通过AutowiredAnnotationBeanPostProcessor进行解析根据类型resolveDependency查找匹配的 Bean可能触发递归创建通过反射Field.set()或Method.invoke()注入Aware 回调如果 Bean 实现了BeanNameAware、BeanFactoryAware等接口容器会调用对应方法传入自身引用。BeanPostProcessor典型的应用如ApplicationContextAwareProcessor注入ApplicationContextAbstractAutoProxyCreator生成 AOP 代理。3. 完成并存入缓存初始化完成后单例 Bean 会被放入单例池DefaultSingletonBeanRegistry中的singletonObjectsConcurrentHashMapString, Object原型 Bean 不会缓存每次获取都会重新创建四、Bean 的完整生命周期结合源码顺序1. 解析得到 BeanDefinition 2. 实例化构造器 3. 依赖注入填充属性 4. 设置 BeanNameBeanNameAware 5. 设置 BeanFactoryBeanFactoryAware 6. 设置 ApplicationContextApplicationContextAware 7. BeanPostProcessor.beforeInitialization 8. 执行初始化方法PostConstruct、afterPropertiesSet、init-method 9. BeanPostProcessor.afterInitialization 10. 注册销毁回调DisposableBean、PreDestroy、destroy-method 11. Bean 就绪使用中 12. 容器关闭时调用销毁方法Bean 生命周期全流程以单例非懒加载 Bean为例结合 Spring 源码关键步骤实例化 InstantiationcreateBeanInstance()通过构造器或工厂方法创建对象实例此时属性未设置但对象已存在。属性填充 PopulatepopulateBean()执行 DI如上节所述。此时会解析循环依赖并提前暴露早期对象。Aware 接口回调如果 Bean 实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAwareSpring 会调用对应方法。但注意这些回调发生在属性填充之后初始化之前。BeanPostProcessor 前置处理调用所有BeanPostProcessor.postProcessBeforeInitialization()。例如ApplicationContextAwareProcessor会在这一步注入ApplicationContext。初始化 Initialization如果 Bean 实现了InitializingBean调用afterPropertiesSet()。如果配置了init-method或PostConstruct调用指定的初始化方法。PostConstruct由CommonAnnotationBeanPostProcessor处理实际也是在postProcessBeforeInitialization中触发的。BeanPostProcessor 后置处理调用postProcessAfterInitialization()这是 AOP 动态代理的“着床点”之一如AbstractAutoProxyCreator在这里生成代理对象。Bean 就绪存入singletonObjects一级缓存可供应用程序使用。销毁 Destruction容器关闭时如果实现了DisposableBean调用destroy()。如果配置了destroy-method或PreDestroy调用指定方法。注意作用域为prototype的 Bean 创建后容器不再管理其生命周期不会调用销毁方法。五、循环依赖的解决原理纯 Singleton 字段注入场景示例ComponentpublicclassA{AutowiredprivateBb;}ComponentpublicclassB{AutowiredprivateAa;}Spring 解决方法三级缓存概述一级缓存singletonObjects已完全初始化好的单例 Bean二级缓存earlySingletonObjects提前暴露的原始对象尚未填充属性三级缓存singletonFactoriesObjectFactory工厂用于生成提前暴露的 Bean可被 AOP 增强执行流程创建 A实例化 A无依赖得到原始对象aRaw将aRaw包装成ObjectFactory放入三级缓存。注入 B发现 A 依赖 B开始创建 B。创建 B实例化 B得到bRaw放入三级缓存发现 B 依赖 A从一级 → 二级 → 三级查找。从三级缓存中拿到 A 的工厂调用getEarlyBeanReference()得到 A 的早期引用如果 A 需要 AOP此处生成代理对象放入二级缓存并删除三级缓存。B 成功获得 A 的早期引用可能为原始对象或代理对象完成 B 的属性注入接着初始化 B最终 B 进入一级缓存。回到 A现在 B 已经创建完成A 完成属性注入再执行 A 的初始化最终 A 也进入一级缓存。关键点只支持单例singleton作用域的字段注入或 Setter 注入的循环依赖。构造器注入无法解决因为实例化时就要求依赖存在。循环依赖的解决方案详解Spring 通过三级缓存解决大部分单例 Bean 的循环依赖仅限 Setter/字段注入构造器注入无法解决。1. 三级缓存数据结构定义在DefaultSingletonBeanRegistry/** 一级缓存已完成初始化的单例Bean */privatefinalMapString,ObjectsingletonObjectsnewConcurrentHashMap(256);/** 二级缓存早期暴露的Bean尚未填充属性但已实例化 */privatefinalMapString,ObjectearlySingletonObjectsnewHashMap(16);/** 三级缓存单例工厂用于生成早期暴露的Bean可产生代理 */privatefinalMapString,ObjectFactory?singletonFactoriesnewHashMap(16);2. 解决流程举例A 依赖 BB 依赖 A通过 Setter 注入开始创建 AgetBean(a)→doGetBean()→ 检测singletonObjects无 → 标记 A 为“正在创建” → 调用createBean(a)。实例化 AcreateBeanInstance()得到 A 的原始对象未填充属性。关键步骤提前暴露 A 到三级缓存addSingletonFactory(a,()-getEarlyBeanReference(a,mbd,bean));ObjectFactory中封装了getEarlyBeanReference方法该方法会调用SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference()用于处理代理如 AOP。进入populateBean(a)发现 A 需要注入 B →resolveDependency()→getBean(b)。创建 B同样步骤实例化 B → 提前暴露 B 到三级缓存 → 填充 B 的属性时发现需要注入 A。getBean(a)再次被调用此时一级缓存无 A但 A 处于“正在创建”状态。Spring 发现当前创建中集合里有 A尝试从二级缓存或三级缓存中获取getSingleton(a, true)→先查二级缓存earlySingletonObjects为空再从三级缓存拿到ObjectFactory调用getObject()得到 A 的早期引用可能被代理将该早期引用放入二级缓存并删除三级缓存中的工厂。B 拿到 A 的早期引用尚未完成初始化B 继续完成属性填充和初始化完成后将 B 放入一级缓存。回到 A 的populateBean()B 已经就绪成功注入 → 继续执行 A 的初始化流程。A 初始化完成后将 A 放入一级缓存并删除二、三级缓存中的相关记录。3. 为什么需要三级缓存二级不够吗二级缓存可以存储早期暴露的半成品对象解决循环依赖但如果循环依赖涉及 AOP 代理则必须借助三级缓存。因为 AOP 代理通常是在BeanPostProcessor.postProcessAfterInitialization()中创建而循环依赖发生时对象尚在初始化过程中需要一个在创建代理对象之前就能获取到正确代理的机制。三级缓存中的ObjectFactory调用getEarlyBeanReference()该钩子允许 AOP 后处理器提前生成代理并暴露出来而不是等到初始化完成。如果没有三级缓存就只能在二级缓存中提前放入原始对象导致最终注入的可能是原始对象而非代理对象。4. 无法解决的循环依赖场景构造器注入因为实例化阶段就需要依赖对方无法提前暴露。使用Lazy可打破循环延迟依赖加载prototype作用域Spring 不缓存原型 Bean每次请求都创建新实例遇到循环依赖会直接抛出BeanCurrentlyInCreationException。Async或某些创建代理的后处理器生效前有时需要额外配置但通常上述三级缓存已能处理普通 AOP。5. 其他辅助机制可以通过Lazy注解在依赖的字段或构造参数上加上LazySpring 会注入一个代理对象实际调用时再创建真实 Bean。也可以通过PostConstructApplicationContext.getBean()延迟获取。六、AOP 与 IoC 的协作当 Bean 被 AOP 增强如Transactional、Async时BeanPostProcessor例如AnnotationAwareAspectJAutoProxyCreator会在postProcessAfterInitialization阶段判断是否匹配切点。如果匹配则返回一个代理对象CGLIB 或 JDK 动态代理并覆盖原来的原始对象。因此最终放入singletonObjects缓存的是代理对象对外暴露的也是代理对象。七、FactoryBean 的特殊处理实现FactoryBean接口的 Bean 本身是一个工厂调用getBean(beanName)返回工厂实例调用getBean(beanName)返回FactoryBean.getObject()生成的对象。Spring 内部通过FactoryBeanRegistrySupport管理避免重复调用getObject()。八、底层技术支撑技术用途反射java.lang.reflect调用构造器、方法、设置字段CGLIB动态生成子类实现代理或实例化如没有无参构造时ConcurrentHashMap存储单例池、BeanDefinition 注册表等缓存LinkedHashSet记录正在创建中的 Bean 名称用于循环依赖检测策略模式InstantiationStrategy隔离实例化细节观察者模式ApplicationEvent多播器九、总结一句话Spring IoC 底层是基于BeanDefinition元数据、三级缓存、反射与动态代理通过BeanPostProcessor扩展点实现对象的全生命周期管理和依赖注入的核心容器。Spring IOC 底层建立在精密的 BeanDefinition 注册、BeanFactory 缓存、BeanPostProcessor 扩展点之上。循环依赖的关键在于三级缓存 提前暴露工厂它能兼顾普通对象和代理对象的早期引用。理解这些原理对于性能调优、排查 Bean 创建失败异常以及自定义扩展都至关重要。