Spring IOC的加载流程

Spring IOC(控制反转)容器的核心作用是管理 Bean 的生命周期,从加载配置、解析 Bean 定义,到创建、初始化 Bean,最终将可用的 Bean 提供给应用。整个加载流程可以分为容器初始化Bean 实例化两大阶段,具体步骤如下(以最常用的ClassPathXmlApplicationContext为例):

一、容器初始化阶段:加载并解析配置,注册 Bean 定义

这一阶段不创建 Bean 实例,只完成 “Bean 的元数据收集和注册”,相当于 “根据图纸准备好所有零件的清单”。

1. 定位资源(Resource)

容器首先要找到配置文件的位置(比如 XML 文件、注解类),这些配置描述了 “要创建哪些 Bean” 以及 “Bean 的依赖关系”。

  • 例如:new ClassPathXmlApplicationContext("spring.xml") 会从类路径下找到 spring.xml 文件。
  • 资源可以是本地文件、网络资源、类路径资源等,Spring 通过Resource接口统一处理。
2. 加载与解析 BeanDefinition

容器读取配置文件,将其中的 Bean 信息(如类名、属性、依赖、作用域等)解析成BeanDefinition 对象(Bean 的 “元数据”,相当于 “零件图纸”)。

  • 解析 XML:比如 <bean id="userService" class="com.xxx.UserService"> 会被解析成一个 BeanDefinition,记录id=userServiceclass=UserService等信息。
  • 解析注解:比如@Service@Component注解的类,会被扫描并解析成 BeanDefinition。
  • 解析内容:包括 Bean 的类名、作用域(单例 / 原型)、依赖的 Bean、初始化方法(init-method)、销毁方法(destroy-method)等。
3. 注册 BeanDefinition

解析后的 BeanDefinition 会被注册到BeanDefinitionRegistry(Bean 定义注册表,本质是一个 Map)中,key 是 Bean 的名称(如userService),value 是对应的 BeanDefinition。

  • 此时容器中只有 “图纸”(BeanDefinition),还没有实际的 Bean 对象。
  • 例如:注册后,容器知道 “有一个叫 userService 的 Bean,对应的类是 UserService,需要依赖 userDao”。
4. 调用 BeanFactoryPostProcessor(后置处理器)

这是容器初始化的最后一步,允许对已注册的 BeanDefinition 进行修改或增强(比如替换属性值、添加新定义等)。

  • 典型例子:PropertyPlaceholderConfigurer 会替换配置中的占位符(如 ${db.url} 替换成实际的数据库地址)。
  • 执行完这一步,BeanDefinition 的信息就固定了,接下来将基于这些信息创建 Bean。

二、Bean 实例化阶段:创建并初始化 Bean

这一阶段根据注册的 BeanDefinition,真正创建 Bean 对象,完成依赖注入和初始化,相当于 “根据图纸造出零件并组装好”。

1. 实例化 Bean(创建对象)

容器根据 BeanDefinition 的信息,通过反射创建 Bean 的实例(调用类的构造方法)。

  • 单例 Bean:默认在容器启动时就实例化(除非设置lazy-init="true"延迟加载)。
  • 原型 Bean:每次调用getBean()时才实例化。
  • 例如:对UserService的 BeanDefinition,容器会执行 UserService service = new UserService() 创建实例。
2. 依赖注入(属性填充)

实例化后,容器会给 Bean 的属性赋值(包括依赖的其他 Bean),即 “依赖注入”(DI)。

  • 例如:UserService 依赖 UserDao,容器会从自己管理的 Bean 中找到userDao实例,通过 setter 方法(setUserDao(userDao))或字段注入(@Autowired)设置给UserService
  • 这里会处理循环依赖(如 A 依赖 B,B 依赖 A),通过三级缓存提前暴露半成品 Bean 解决(详见之前的循环依赖讲解)。
3. 初始化 Bean(增强与就绪)

属性注入后,Bean 还需要经过一系列初始化操作才能 “可用”:

  • 调用 Aware 接口:如果 Bean 实现了BeanNameAwareApplicationContextAware等接口,容器会传入对应的信息(如 Bean 的名称、ApplicationContext 对象)。
  • 调用 BeanPostProcessor 前置方法:容器中的BeanPostProcessor(Bean 后置处理器)会对 Bean 进行前置处理(如 AOP 代理的准备工作)。
  • 调用初始化方法:执行自定义的初始化逻辑,包括:
    • 实现InitializingBean接口的afterPropertiesSet()方法;
    • 配置中指定的init-method(如<bean init-method="init"/>)。
  • 调用 BeanPostProcessor 后置方法:完成最终增强(如 AOP 动态代理就是在这里生成代理对象,替换原始 Bean)。
4. Bean 就绪,放入缓存

初始化完成后,单例 Bean会被放入一级缓存(singletonObjects),供后续使用;原型 Bean则直接返回给调用者(不存入缓存)。

  • 此时,通过context.getBean("userService")就能获取到完全可用的UserService实例了。

三、容器关闭阶段:销毁 Bean

当容器关闭时(如调用close()方法),会触发 Bean 的销毁流程:

  • 调用DisposableBean接口的destroy()方法;
  • 调用配置中指定的destroy-method(如<bean destroy-method="destroy"/>)。

总结:Spring IOC 加载核心流程

  1. 找配置:定位资源(XML / 注解);
  2. 读配置:解析成 BeanDefinition(元数据);
  3. 记配置:注册 BeanDefinition 到注册表;
  4. 改配置:通过 BeanFactoryPostProcessor 修改定义;
  5. 造对象:实例化 Bean(反射创建);
  6. 填依赖:依赖注入(设置属性和依赖 Bean);
  7. 做初始化:执行 Aware 接口、初始化方法、后置处理器增强;
  8. 用 Bean:单例 Bean 入缓存,供应用使用;
  9. 清资源:容器关闭时销毁 Bean。

整个流程体现了 “控制反转” 的核心:应用不需要自己new对象,而是由 IOC 容器统一创建、组装和管理,降低了代码耦合度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值