Spring IOC 核心原理

核心定位:搞懂 Spring IOC 容器的启动逻辑、Bean 的创建与管理流程,明确“Spring 底层如何干活”,是 Spring 所有特性的基础。

一、容器核心接口:BeanFactory vs ApplicationContext

核心结论:两者都是 IOC 容器核心接口,ApplicationContext 是 BeanFactory 的子接口,功能更完善,日常开发关注后者。

对比维度 BeanFactory ApplicationContext
加载方式 懒加载(getBean 时才创建 Bean) 预加载(容器启动时就创建所有 singleton Bean)
功能范围 基础功能:Bean 的创建、获取、管理,无额外扩展 继承 BeanFactory 所有功能,新增:国际化、事件发布、资源加载、AOP 集成等
常见实现类 XmlBeanFactory(已过时)、DefaultListableBeanFactory ClassPathXmlApplicationContext、AnnotationConfigApplicationContext(最常用)
关键点 体现 IOC 最基础的“控制反转”思想 “懒加载 vs 预加载”

二、IOC 容器启动流程 🔴

核心逻辑:加载配置 → 解析 Bean 定义 → 初始化容器 → 创建 Bean(预加载 singleton),简化时序如下(面试可直接口述):

  1. 加载配置资源:读取 XML、注解(@Component、@Configuration)、JavaConfig 等配置,获取 Bean 的定义信息(BeanDefinition)。

  2. 解析与注册 Bean:将配置中的 Bean 信息解析为 BeanDefinition 对象,注册到 BeanDefinitionRegistry(Bean 定义注册表)。

  3. 执行 BeanFactoryPostProcessor:对 BeanDefinition 进行修改(如修改 Bean 属性、新增 Bean),在 Bean 实例化之前执行

  4. 初始化 Bean:根据 BeanDefinition 创建 Bean 实例(singleton 预加载,prototype 懒加载),执行依赖注入、初始化方法。

  5. 容器启动完成:Bean 已就绪,可通过容器获取 Bean 并使用。

重点:“配置加载→Bean定义注册→Bean初始化”三个核心步骤,BeanFactoryPostProcessor 的执行时机。

三、Bean 完整生命周期 🟠

核心流程:实例化 → 属性注入 → 初始化 → 销毁(4个核心阶段),补充完整执行顺序(结合扩展点):

  1. 实例化(Instantiation):通过构造器创建 Bean 实例(内存分配,此时 Bean 还未注入属性)。

  2. 属性注入(Populate):将容器中配置的依赖(@Autowired、XML 配置)注入到 Bean 实例中。

  3. 执行 Aware 接口方法:若 Bean 实现了 Aware 接口(如 BeanNameAware、BeanFactoryAware),容器会注入对应的资源(如 Bean 名称、BeanFactory)。

  4. 执行 BeanPostProcessor#postProcessBeforeInitialization:初始化前增强(所有 Bean 都会执行,可自定义扩展)。

  5. 初始化(Initialization):

    • 执行 @PostConstruct 注解方法(JSR-250 规范);

    • 执行 InitializingBean 接口的 afterPropertiesSet() 方法;

    • 执行 XML 配置/JavaConfig 中定义的 init-method 方法。

  6. 执行 BeanPostProcessor#postProcessAfterInitialization:初始化后增强(如 AOP 动态代理,在这里生成代理对象)。

  7. Bean 就绪:可正常使用(singleton 存于容器缓存,prototype 每次获取都新建)。

  8. 销毁(Destruction):

    • 执行 @PreDestroy 注解方法;

    • 执行 DisposableBean 接口的 destroy() 方法;

    • 执行 XML 配置/JavaConfig 中定义的 destroy-method 方法;

    • 容器关闭时,singleton Bean 会被销毁,prototype Bean 由开发者手动销毁。

流程:实例化 → 注属性 → Aware → 前置增强 → 初始化 → 后置增强 → 就绪 → 销毁

四、@Lazy 懒加载 & Bean 作用域

1. @Lazy 懒加载

  • 作用:改变 singleton Bean 的加载时机,从“容器启动预加载”改为“第一次 getBean 时加载”。

  • 适用场景:Bean 初始化耗时、占用资源多,且启动时不使用(如后台定时任务、非核心服务)。

  • 注意:仅对 singleton 作用域有效,prototype 本身就是懒加载(每次获取都新建)。

2. Bean 作用域(5种,重点记前2种)

作用域 说明 适用场景
singleton(默认) 容器中仅存在一个 Bean 实例,所有请求共享,线程不安全(需注意全局变量) 无状态 Bean(如 Service、Dao),日常开发90%以上场景
prototype 每次 getBean 都创建新实例,容器不管理销毁(开发者手动处理) 有状态 Bean(如 Controller 中接收请求参数的对象、线程不安全的 Bean)
request 每个 HTTP 请求创建一个实例,请求结束后销毁(仅 Web 环境有效) Web 场景,存储请求级别的数据
session 每个 HTTP Session 创建一个实例,session 失效后销毁(仅 Web 环境有效) Web 场景,存储会话级别的数据(如用户登录信息)
application 整个 Web 应用生命周期内只有一个实例(与 singleton 区别:application 是 Web 容器级,singleton 是 Spring 容器级) Web 应用全局共享的 Bean(如全局配置)

五、依赖注入方式对比(最佳实践)

核心:Spring 支持3种依赖注入方式,重点“推荐用法”和“避坑点”。

注入方式 实现方式 优点 缺点 最佳实践
构造器注入 @Autowired 标注构造器,或无注解(Spring 5.0+ 自动注入) 强制依赖必须注入,避免空指针;Bean 实例化后即完整可用;支持 immutable 变量 依赖过多时,构造器参数过长,代码不简洁 推荐!依赖少(1-3个)时首选,适合强制依赖
Setter 注入 @Autowired 标注 Setter 方法 代码简洁;支持可选依赖(可设置默认值);灵活性高 Bean 实例化后可能未注入依赖,存在空指针风险;不支持 immutable 变量 可选依赖时使用,配合 @Nullable 注解标注可选参数
字段注入 @Autowired 直接标注字段(最简洁) 代码极简,开发效率高 耦合度高;无法注入 final 字段;单元测试难以Mock;不支持依赖注入的清晰性 不推荐!仅临时测试、简单demo可用,生产环境避免使用

重点:说出“构造器注入首选”,并说明原因(强制依赖、避免空指针),同时区分三种方式的优缺点。

六、关键扩展点:BeanFactoryPostProcessor vs BeanPostProcessor

核心区别:执行时机不同、作用对象不同,是 Spring 扩展的核心。

对比维度 BeanFactoryPostProcessor BeanPostProcessor
执行时机 Bean 实例化 之前(仅执行一次,针对所有 BeanDefinition) Bean 实例化、属性注入 之后,初始化前后(每个 Bean 都执行一次)
作用对象 BeanDefinition(Bean 的定义信息) Bean 实例本身
核心作用 修改 BeanDefinition(如修改 Bean 属性、新增 Bean、替换 Bean 定义) 对 Bean 实例进行增强(如修改 Bean 属性、生成代理对象)
常见实现 PropertyPlaceholderConfigurer(解析占位符 ${}) AutowiredAnnotationBeanPostProcessor(处理 @Autowired 注入)、AOP 代理增强处理器
记忆技巧 “改定义”:在 Bean 没创建前,修改它的“蓝图” “改实例”:Bean 已经创建,对它进行加工增强

七、补充:FactoryBean 与 BeanFactory 区别 🟠

1. BeanFactory

  • 本质:IOC 容器的核心接口,负责管理所有 Bean 的创建、获取、生命周期。

  • 角色:“容器管理者”,管理的是所有普通 Bean。

2. FactoryBean

  • 本质:一个 Bean(实现 FactoryBean 接口的 Bean),不是容器。

  • 角色:“Bean 工厂”,负责创建特定的 Bean(如复杂对象、代理对象)。

  • 核心方法:getObject() → 返回真正需要的 Bean 实例;getObjectType() → 返回 Bean 类型。

3. 核心区别

BeanFactory 是“容器”,管理所有 Bean;FactoryBean 是“Bean”,负责创建某一个特定的 Bean。

示例:Spring 中 AOP 的 ProxyFactoryBean、MyBatis 的 SqlSessionFactoryBean,都是 FactoryBean,用于创建复杂的代理对象/工厂对象。

八、补充:Aware 接口作用

  • 核心作用:让 Bean 主动获取 Spring 容器中的资源(如 Bean 名称、BeanFactory、ApplicationContext),打破“控制反转”的封闭性。

  • 常见 Aware 接口(记重点3个):

    • BeanNameAware:获取当前 Bean 的名称;

    • BeanFactoryAware:获取 BeanFactory 容器实例;

    • ApplicationContextAware:获取 ApplicationContext 容器实例(功能最全)。

  • 注意:Aware 接口的方法由 Spring 容器自动调用,无需手动调用;仅当 Bean 实现该接口时,才会注入对应资源。

总结

  1. BeanFactory 与 ApplicationContext 区别:懒加载 vs 预加载、功能多少;

  2. IOC 容器启动流程:配置加载 → BeanDefinition 注册 → 初始化 Bean;

  3. Bean 生命周期:实例化 → 属性注入 → 初始化 → 销毁(结合扩展点);

  4. 依赖注入首选构造器注入,避免字段注入;

  5. BeanFactoryPostProcessor(改定义)与 BeanPostProcessor(改实例)的执行时机和作用。