文章目录
前言
对于一个长期的spring使用者来说,对于spring 的生命周期不是很了解,所以趁着这个疫情比较严重的时候,在家静下心来,看一下这个很久困在心中的一个问题。
生命周期
它大致分为Bean 定义
、Bean 的初始化
、Bean 的生存期
和Bean的销毁
4 个部分。其中Bean 定义过程大致如下:
- Spring 通过我们的配置,如
@ComponentScan
定义的扫描路径去找到带有@Component
的类,这个过程就是一个资源定位的过程。 - 一旦找到了资源,那么它就开始解析,并且将定义的信息保存起来。注意,此时还没有初始化
Bean
,也就没有Bean
的实例,它有的仅仅是Bean
的定义。 - 然后就会把
Bean
定义发布到Spring IoC
容器中。此时,IoC
容器也只有Bean
的定义,还是没有Bean
的实例生成。
完成了这3 步只是一个资源定位并将Bean
的定义发布到IoC
容器的过程,还没有Bean
实例的生成,更没有完成依赖注入。在默认的情况下, Spring
会继续去完成Bean
的实例化和依赖注入,这样从IoC
容器中就可以得到一个依赖注入完成的Bean
。但是,有些Bean
会受到变化因素的影响,这
时我们倒希望是取出Bean
的时候完成初始化和依赖注入,换句话说就是让那些Bean
只是将定义发布到IoC
容器而不做实例化和依赖注入, 当我们取出来的时候才做初始化和依赖注入等操作。
ComponentScan
中还有一个配置项lazyI init
,只可以配置Boolean
值,且默认值为false
,也就是默认不进行延迟初始化,因此在默认的情况下Spring
会对Bean
进行实例化和依赖注入对应的属性值。
详细描述
bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean 被销毁,可以总结为以下七个阶段:
- 处理名称,检查缓存
- 处理父子容器
- 处理 dependsOn
- 选择 scope 策略
- 创建 bean
- 类型转换处理
- 销毁 bean
处理名称,检查缓存
- 这一步会处理别名,将别名解析为实际名称
- 对 FactoryBean 也会特殊处理,如果以 & 开头表示要获取 FactoryBean 本身,否则表示要获取其产品
- 这里针对单例对象会检查一级、二级、三级缓存
- singletonFactories 三级缓存,存放单例工厂对象
- earlySingletonObjects 二级缓存,存放单例工厂的产品对象
- 如果发生循环依赖,产品是代理;无循环依赖,产品是原始对象
- singletonObjects 一级缓存,存放单例成品对象
处理父子容器
- 如果当前容器根据名字找不到这个 bean,此时若父容器存在,则执行父容器的 getBean 流程
- 父子容器的 bean 名称可以重复
处理 dependsOn
- 如果当前 bean 有通过 dependsOn 指定了非显式依赖的 bean,这一步会提前创建这些 dependsOn 的 bean
- 所谓非显式依赖,就是指两个 bean 之间不存在直接依赖关系,但需要控制它们的创建先后顺序
选择 scope 策略
- 对于 singleton scope,首先到单例池去获取 bean,如果有则直接返回,没有再进入创建流程
- 对于 prototype scope,每次都会进入创建流程
- 对于自定义 scope,例如 request,首先到 request 域获取 bean,如果有则直接返回,没有再进入创建流程
创建 bean - 创建 bean 实例
要点 | 总结 |
---|---|
有自定义 TargetSource 的情况 | 由 AnnotationAwareAspectJAutoProxyCreator 创建代理返回 |
Supplier 方式创建 bean 实例 | 为 Spring 5.0 新增功能,方便编程方式创建 bean 实例 |
FactoryMethod 方式 创建 bean 实例 | ① 分成静态工厂与实例工厂;② 工厂方法若有参数,需要对工厂方法参数进行解析,利用 resolveDependency;③ 如果有多个工厂方法候选者,还要进一步按权重筛选 |
AutowiredAnnotationBeanPostProcessor | ① 优先选择带 @Autowired 注解的构造;② 若有唯一的带参构造,也会入选 |
mbd.getPreferredConstructors | 选择所有公共构造,这些构造之间按权重筛选 |
采用默认构造 | 如果上面的后处理器和 BeanDefiniation 都没找到构造,采用默认构造,即使是私有的 |
创建 bean - 依赖注入
要点 | 总结 |
---|---|
AutowiredAnnotationBeanPostProcessor | 识别 @Autowired 及 @Value 标注的成员,封装为 InjectionMetadata 进行依赖注入 |
CommonAnnotationBeanPostProcessor | 识别 @Resource 标注的成员,封装为 InjectionMetadata 进行依赖注入 |
resolveDependency | 用来查找要装配的值,可以识别:① Optional;② ObjectFactory 及 ObjectProvider;③ @Lazy 注解;④ @Value 注解(${ }, #{ }, 类型转换);⑤ 集合类型(Collection,Map,数组等);⑥ 泛型和 @Qualifier(用来区分类型歧义);⑦ primary 及名字匹配(用来区分类型歧义) |
AUTOWIRE_BY_NAME | 根据成员名字找 bean 对象,修改 mbd 的 propertyValues,不会考虑简单类型的成员 |
AUTOWIRE_BY_TYPE | 根据成员类型执行 resolveDependency 找到依赖注入的值,修改 mbd 的 propertyValues |
applyPropertyValues | 根据 mbd 的 propertyValues 进行依赖注入(即xml中 <property name ref|value/> ) |
创建 bean - 初始化
要点 | 总结 |
---|---|
内置 Aware 接口的装配 | 包括 BeanNameAware,BeanFactoryAware 等 |
扩展 Aware 接口的装配 | 由 ApplicationContextAwareProcessor 解析,执行时机在 postProcessBeforeInitialization |
@PostConstruct | 由 CommonAnnotationBeanPostProcessor 解析,执行时机在 postProcessBeforeInitialization |
InitializingBean | 通过接口回调执行初始化 |
initMethod | 根据 BeanDefinition 得到的初始化方法执行初始化,即 <bean init-method> 或 @Bean(initMethod) |
创建 aop 代理 | 由 AnnotationAwareAspectJAutoProxyCreator 创建,执行时机在 postProcessAfterInitialization |
创建 bean - 注册可销毁 bean
在这一步判断并登记可销毁 bean
- 判断依据
- 如果实现了 DisposableBean 或 AutoCloseable 接口,则为可销毁 bean
- 如果自定义了 destroyMethod,则为可销毁 bean
- 如果采用 @Bean 没有指定 destroyMethod,则采用自动推断方式获取销毁方法名(close,shutdown)
- 如果有 @PreDestroy 标注的方法
- 存储位置
- singleton scope 的可销毁 bean 会存储于 beanFactory 的成员当中
- 自定义 scope 的可销毁 bean 会存储于对应的域对象当中
- prototype scope 不会存储,需要自己找到此对象销毁
- 存储时都会封装为 DisposableBeanAdapter 类型对销毁方法的调用进行适配
类型转换处理
- 如果 getBean 的 requiredType 参数与实际得到的对象类型不同,会尝试进行类型转换
销毁 bean
- 销毁时机
- singleton bean 的销毁在 ApplicationContext.close 时,此时会找到所有 DisposableBean 的名字,逐一销毁
- 自定义 scope bean 的销毁在作用域对象生命周期结束时
- prototype bean 的销毁可以通过自己手动调用 AutowireCapableBeanFactory.destroyBean 方法执行销毁
- 同一 bean 中不同形式销毁方法的调用次序
- 优先后处理器销毁,即 @PreDestroy
- 其次 DisposableBean 接口销毁
- 最后 destroyMethod 销毁(包括自定义名称,推断名称,AutoCloseable 接口 多选一)