Spring 的 IoC(Inversion of Control,控制反转) 是 Spring 框架的核心思想之一,它的本质是将对象的创建、管理、依赖关系的维护交给 Spring 容器来完成,而不是由开发者手动去 new 或管理。


🧠 一、IoC 实现原理概览

✅ 控制反转(IoC)是什么?

  • 传统方式:对象之间相互 new,耦合度高。
  • IoC 方式:对象的创建和依赖关系由容器来管理,程序只负责声明“需要什么”,而“怎么创建”由容器决定。

✅ 依赖注入(DI)与 IoC 的关系?

  • DI 是实现 IoC 的一种方式。
  • Spring 使用 DI 来实现 IoC,即通过配置(XML 或注解)来描述对象之间的依赖关系,容器在运行时自动装配这些依赖。

📦 二、IoC 容器核心组件

Spring IoC 容器主要包括以下核心接口和类:

类名 作用
BeanFactory 最基础的容器接口,提供基本的 IOC 功能
ApplicationContext BeanFactory 的子接口,提供更多企业级功能(如 AOP、国际化等)
BeanDefinition 描述一个 Bean 的元信息(如类名、作用域、是否懒加载等)
BeanPostProcessor 在 Bean 初始化前后进行拦截处理
BeanFactoryPostProcessor 在容器加载完 BeanDefinition 后修改其配置

🔁 三、IoC 容器启动流程(以 ApplicationContext 为例)

Spring 启动过程中最重要的方法是 refresh(),它定义了整个容器的初始化流程。

public void refresh() throws BeansException, IllegalStateException {
    prepareRefresh();
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    prepareBeanFactory(beanFactory);
    postProcessBeanFactory(beanFactory);
    invokeBeanFactoryPostProcessors(beanFactory); // 修改 BeanDefinition
    registerBeanPostProcessors(beanFactory);      // 注册后置处理器
    initMessageSource();                          // 初始化消息资源
    initApplicationEventMulticaster();            // 初始化事件广播器
    onRefresh();                                  // 子类扩展点
    registerListeners();                          // 注册监听器
    finishBeanFactoryInitialization(beanFactory); // 实例化单例 Bean
    finishRefresh();                              // 刷新完成
}

其中最重要的一步是 finishBeanFactoryInitialization(beanFactory),它会触发所有非懒加载的单例 Bean 的实例化。


⚙️ 四、Bean 的生命周期详解

Spring 中每个 Bean 都会经历从定义到销毁的一系列阶段,以下是主要流程:

🔄 Bean 生命周期步骤

  1. 加载 BeanDefinition
    • 从 XML、注解或 Java Config 中解析出 Bean 的元数据。
  2. 实例化 Bean
    • 调用构造函数创建 Bean 对象(此时还未赋值属性)
  3. 填充属性(依赖注入)
    • 根据配置自动装配依赖(@Autowired、set 方法等)
  4. 设置 BeanName、BeanFactory、ApplicationContext 等
    • 实现 BeanNameAware, BeanFactoryAware 接口的方法回调
  5. 调用 BeanPostProcessor.beforeInitialization()
  6. 调用初始化方法
    • @PostConstruct
    • InitializingBean.afterPropertiesSet()
    • 自定义 init-method
  7. 调用 BeanPostProcessor.afterInitialization()
  8. 使用 Bean
  9. 销毁 Bean
    • @PreDestroy
    • DisposableBean.destroy()
    • 自定义 destroy-method

🧱 五、IoC 实现的关键技术点

1. BeanDefinition 的注册

  • Spring 容器在启动时会扫描类路径下的类或 XML 配置文件,生成 BeanDefinition 并注册到 BeanFactory 中。

2. 依赖注入(DI)机制

  • Spring 通过反射机制调用 setter 方法或构造函数注入依赖。
  • 支持按类型、按名称注入。
  • 常见注解:
    • @Autowired
    • @Resource
    • @Inject

3. 三级缓存解决循环依赖

  • Spring 解决的是 单例 Bean 的构造方法之外的循环依赖问题
  • 三级缓存结构如下:
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 一级缓存
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);       // 二级缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
    
  • 当发现循环依赖时,Spring 会提前暴露一个工厂对象放入三级缓存中,后续获取该 Bean 时再通过工厂创建代理对象。

4. BeanFactoryPostProcessor 和 BeanPostProcessor

  • BeanFactoryPostProcessor:可以修改 BeanDefinition
  • BeanPostProcessor:可以在 Bean 实例化前后对其进行增强处理(例如 AOP)

📌 六、代码示例分析

示例 1:简单 Bean 加载流程

@Component
class A {
    @Autowired
    B b;
}

@Component
class B {
    @Autowired
    A a;
}

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        A a = context.getBean(A.class);
        a.b.doSomething();
    }
}

在这个例子中,A 和 B 相互依赖,Spring 使用三级缓存机制解决了这个循环依赖问题。


📚 七、推荐源码阅读路径

📁 核心类路径(spring-beans、spring-context 模块):

  • AbstractApplicationContext.refresh() —— 容器启动入口
  • DefaultListableBeanFactory —— 默认的 BeanFactory 实现
  • AbstractBeanFactory.getBean() —— 获取 Bean 的主逻辑
  • AbstractAutowireCapableBeanFactory.createBean() —— 创建 Bean 的核心方法
  • doCreateBean() —— 实例化 + 属性注入 + 初始化
  • getSingleton() —— 三级缓存相关逻辑
  • populateBean() —— 属性填充(依赖注入)
  • initializeBean() —— 初始化阶段(包括 Aware、BeanPostProcessor)

❓八、常见面试题(结合源码)

Q1: Spring 是如何管理 Bean 的生命周期的?

Spring 通过 BeanFactoryApplicationContext 来管理 Bean 的创建、依赖注入、初始化、销毁等全过程。通过 BeanPostProcessorInitializingBeanDisposableBean 等接口或注解实现扩展。

Q2: Spring 是如何解决循环依赖的?

Spring 使用三级缓存机制,在创建 Bean 的过程中提前暴露一个工厂对象,避免重复创建导致死循环。但仅支持单例 Bean,并且不能处理构造函数注入的循环依赖。

Q3: Spring 是如何实现依赖注入的?

Spring 通过反射机制,读取 @Autowired@Resource 等注解,找到对应的依赖对象并注入。底层使用 Field.set()Method.invoke() 实现。


✅ 总结

特性 Spring IoC 实现
控制反转 将对象创建交给容器管理
依赖注入 支持字段、构造器、Setter 注入
Bean 生命周期 完整的初始化、销毁流程
循环依赖 使用三级缓存机制解决单例 Bean 循环依赖
扩展机制 提供多种扩展点(BeanFactoryPostProcessor、BeanPostProcessor)
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐