Appearance
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 行
