Skip to content

IoC 容器

  IoC(Inversion of Control,控制反转)是 Spring 的核心。 它把"创建对象"和"管理对象依赖关系"的控制权从代码中反转给 Spring 容器。

一、什么是 IoC

传统方式(控制权在代码中):

  public class OrderService {
      private OrderDao orderDao = new OrderDaoImpl();  // 代码主动创建依赖
  }
  // 问题:OrderService 和 OrderDaoImpl 强耦合,换实现要改代码


IoC 方式(控制权在 Spring 容器中):

  @Service
  public class OrderService {
      @Autowired
      private OrderDao orderDao;  // 容器注入,不关心具体实现
  }
  // OrderService 只依赖接口,具体实现由容器管理
IoC 的本质:不要自己找对象,让容器把对象给你

  生活例子:
  传统:你去餐厅 → 自己进厨房 → 找食材 → 做饭
  IoC:你去餐厅 → 坐下 → 服务员端菜上来

  代码例子:
  传统:new OrderDaoImpl() → 主动创建
  IoC:@Autowired OrderDao → 容器注入

二、IoC 容器体系

IoC 容器两大接口:

  BeanFactory(底层容器)
  ├── 懒加载:第一次 getBean() 时才创建
  ├── 功能简单:Bean 的创建、获取、销毁
  └── 适用场景:资源受限环境(如移动端)

  ApplicationContext(高级容器,继承 BeanFactory)
  ├── 预加载:启动时创建所有单例 Bean
  ├── 额外功能:国际化、事件发布、资源加载、环境抽象
  └── 适用场景:大多数企业级应用

2.1 ApplicationContext 常用实现

java
// XML 配置(传统方式)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

// 注解配置(现代方式)
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

// Spring Boot 使用
ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);

2.2 容器启动流程

ApplicationContext 启动流程:

  ① 准备阶段
     - 设置启动时间
     - 设置激活状态
     - 初始化属性源(PropertySources)

  ② 获取 BeanFactory
     - 创建 DefaultListableBeanFactory
     - 加载 Bean 定义(XML 解析 / 注解扫描)

  ③ BeanFactory 后处理
     - 执行 BeanFactoryPostProcessor(如 @Configuration 解析)
     - 注册 BeanPostProcessor

  ④ 初始化消息源、事件广播器

  ⑤ 注册监听器

  ⑥ 实例化所有单例 Bean(非懒加载)
     遍历所有 BeanDefinition → 创建 Bean 实例 → 依赖注入 → 初始化回调

  ⑦ 完成刷新,发布 ContextRefreshedEvent

三、BeanDefinition

  Spring 不是直接操作 Bean 对象,而是通过 BeanDefinition 来描述一个 Bean 的元数据。

java
// BeanDefinition 包含的信息:
BeanDefinition bd = new RootBeanDefinition();

bd.setBeanClassName("com.example.OrderService");  // 全限定类名
bd.setScope("singleton");                          // 作用域
bd.setLazyInit(false);                             // 是否懒加载
bd.setDependsOn("orderDao");                       // 依赖的 Bean
bd.setInitMethodName("init");                      // 初始化方法
bd.setDestroyMethodName("destroy");                // 销毁方法
bd.setPrimary(true);                               // 是否首选
bd.getPropertyValues().add("timeout", 30);         // 属性值
BeanDefinition 的注册来源:

  XML 配置:
    <bean id="orderService" class="com.example.OrderService" scope="singleton"/>
    → XmlBeanDefinitionReader 解析 → 注册 BeanDefinition

  注解扫描:
    @Component / @Service / @Repository / @Controller
    → ClassPathBeanDefinitionScanner 扫描 → 注册 BeanDefinition

  @Bean 方法:
    @Configuration 类中的 @Bean 方法
    → ConfigurationClassPostProcessor 解析 → 注册 BeanDefinition

  @Import:
    @Import(OtherConfig.class) → 导入其他配置类

四、Bean 的注册方式

java
// 方式一:@Component + 包扫描(最常用)
@Component
public class OrderService { }

@Configuration
@ComponentScan("com.example")  // 扫描指定包
public class AppConfig { }

// 方式二:@Bean(适合第三方类)
@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

// 方式三:@Import(快速导入)
@Configuration
@Import({OrderService.class, DataSource.class})
public class AppConfig { }

// 方式四:实现 ImportBeanDefinitionRegistrar(编程式注册)
public class MyRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
                                        BeanDefinitionRegistry registry) {
        BeanDefinition bd = new RootBeanDefinition(OrderService.class);
        registry.registerBeanDefinition("orderService", bd);
    }
}

// 方式五:实现 FactoryBean
@Component
public class MyFactoryBean implements FactoryBean<OrderService> {
    @Override
    public OrderService getObject() { return new OrderService(); }
    @Override
    public Class<?> getObjectType() { return OrderService.class; }
}

五、面试要点

Q1:BeanFactory 和 ApplicationContext 的区别?

  BeanFactory 是底层容器,懒加载,功能简单;ApplicationContext 继承 BeanFactory,预加载单例 Bean,额外提供国际化、事件发布、资源加载等高级功能。日常开发用 ApplicationContext。

Q2:Spring 容器启动时做了什么?

  准备环境 → 创建 BeanFactory → 加载 BeanDefinition → 执行 BeanFactoryPostProcessor → 注册 BeanPostProcessor → 初始化消息源/事件广播器 → 实例化所有单例 Bean → 完成刷新。

Q3:什么是 BeanDefinition?

  BeanDefinition 是 Spring 对 Bean 的元数据描述,包含类名、作用域、是否懒加载、依赖关系、初始化方法等。Spring 通过 BeanDefinition 来创建和管理 Bean。>>> 106 行