1、面试题:Spring Bean的生命周期
即bean从创建到销毁spring做了哪些事情?
阶段5、7比较重要。
spring里面的bean都是懒惰式的初始化,当你第一次去获取它的时候,他才会去创建bean的实例,进行依赖注入、初始化。
阶段1:处理名称,检查缓存
要点
- 掌握别名处理
- 了解FactoryBean的名字规范
- 掌握三级缓存的概念
1、spring当中支持别名,一个bean可以有多个名称。
2、FactoryBean式spring当中专门用来生产其他对象的工厂bean。如果想要获取工厂本身的名称,而不是工厂里里面的bean,需要在名称前面加一个&
总结
- 先把别名解析为实际名称,再进行后续处理
- 若要 FactoryBean本身,需要使用&名称获取
- singletonObjects是一-级缓存, 放单例成品对象
- singletonFactories是三级缓存,放单例工厂
- earlySingletonObjects是二级缓存,放单例工厂的产品,可称为提前单例对象
首先去一级缓存里面查找看有没有创建好的单例对象。如果有,就不用创建了。
二级缓存和三级缓存主要用来解决循环依赖的问题。
三级缓存就可以解决循环依赖问题。那为什么还要二级缓存?
二级缓存是用来解决,需要在代理的情况下还有循环依赖的问题。
阶段2:处理父子容器
要点
- 了解有父容器时的查找规则
当缓存中没有实例对象,也不会立马去创建。如果容器中还配置了父容器,缓存里没有找到,会去父容器里查找这个对象。父容器如果有,就直接使用父容器里面的bean。如果这样还有没,就会走创建的流程。
总结
- 父子容器的 bean名称可以重复
- 优先找子容器的bean,找到了直接返回,找不到继续到父容器找
阶段3: dependsOn
什么是dependsOn?
大部分bena之间都是由依赖关系的,有依赖关系的bean的创建次序是可以得到保障的。例如A依赖于B,那就先创建B,在创建A。
但是有的bean之间没有显式的依赖关系,但是又想控制他们的创建次序,使用A dependsOn B,那就是B先创建后A再创建.
阶段4:按Scope创建bean
要点
- 理解三种scope
singleton,prototype,request,session,
1.单例Bean从refresh被创建,到close被销毁.
2,prototype多例Bean从首次getBean被创建,到调用BeanFactory的destroyBean被销毁.
容器启动refresh和关闭的时候,并不会导致多例bean的创建和销毁.那什么时候多例bean被创建呢?
当调用getBean使用它的时候
创建时间:单例bean是在容器启动refresh式被创建,多例bean是在调用使用她的时候,使用getBean()方法去创建.
销毁时间:单例bean是在容器关闭时,多例bean需要我们自己去调用它的销毁方法.
3,request bean从首次getBean被创建,到request结束前被销毁
创建好了之后放在request作用域,在request作用域销毁之前,将于该域相关的bean销毁.
其实他们三个bean的起点都是从getBean()开始,只不过终点不一样,单例是在容器结束前.基于某一个request Scope的,他是在特定的请求域结束前.至于propotype是自己控制什么时候把它销毁.
总结
- scope 理解为从xXX范围内找这个bean更加贴切
- singleton scope表示从单例池范围内获取bean,如果没有,则创建并放入单例池.
- prototype scope表示从不缓存bean,每次都创建新的
- request scope表示从request对象范围内获取bean,如果没有,则创建并放入request …
阶段5:创建bean
单例对象创建好之后被放入到单例池中,request被放入对应的request域中,propotype哪里都不放,由自己去管理它.
创建阶段 ,依赖注入阶段, 初始化阶段, 注册和销毁bean阶段
每个小阶段都会有对应的beanPostProcessor,对每个阶段的功能进行扩展.比例解析成员变量或者方法上的注解,创建代理对象等.
阶段5-1:创建bean实例
1.优先选择带@Autowired注解的构造器创建实例.
2.若有唯一的带参构造,也会入选
但是如果构造方法是私有的,使用暴力反射,将setS…设为true进行构造.
阶段5-2:依赖注入
bean的实例对象刚创建时,里面空空如也,还不能正常工作.
- 我们的后置处理器只是找到那个成员变量或者成员方法加了@Autowired,@Value注解,找到之后交给InjectionMetadata进行依赖注入.
针对同一个成员采用多种依赖注入的方式,那哪种方式会成功?
按照名字去进行以来注入的时候,是先去除方法的set之后再将方法名首字母小写,就是bean的名字.
即在下面例子中,如果按照名字注入的方式应该是bean3被注入进去.
精确指定注入的bean方式 > 根据名字注入 > AutoWired注解注入
阶段5-3:初始化
首先会处理一些Aware接口,比如一些BeanNameAware接口,BeanFactoryAware接口.
之后调用初始化方法(有三种不同的初始化方式)
@PostConstruct是通过后置处理器CommonAn…调用的.
在beanDedintion里面规定那个方式是初始化方法,可以使用xml配置或者注解@Bean
初始化做的三件事:调用Aware接口,调用初始化方法,创建AOP代理
其中解析注解和创建动态代理都是通过后置处理器帮助实现.
初始化顺序:先是Aware接口 > 注解@PostConstruct > InitalizingBean > initMethod
阶段5-4:注册可销毁bean
要点
- 判断并登记可销毁bean
总结
- 判断依据
- 如果实现了DisposableBean或AutoCloseable接口,则为可销毁bean
- 如果自定义了destroyMethod,则为可销毁bean
- 如果采用@Bean没有指定destroyMethod,则采用自动推断方式获取销毁方法名( close, shutdown)
- 如果有@PreDestroy标注的方法
- 存储位置
- singleton scope的可销毁bean会存储于beanFactory的成员当中
- 自定义scope的可销毁bean会存储于对应的域对象当中
- prototype scope不会存储,需要自己找到此对象销毁
- 存 储时都会封装为DisposableBeanAdapter类型对销毁方法的调用进行适配
阶段6:类型转换
要点
- 如果getBean的requiredType参数与实际得到的对象类型不同,会尝试进行类型转换
这个时候Bean已经被创建返回.
阶段7:销毁bean
要点
- singleton bean的销毁时机
- 自定义scope bean的销毁时机
- prototype bean的销毁时机
- 同一bean中不同形式销毁方法的调用次序
总结
- singleton bean的销毁在ApplicationContext.close 时,此时会找到所有DisposableBean的名字,逐-销毁
- 自定义scope bean的销毁在作用域对象生命周期结束时(例如request)
- prototype bean的销毁可以通过自己手动调用AutowireCapableBeanFactory.destroyBean方法执行销毁
- 同一bean中不同形式销毁方法的调用次序
- 优先后处理器销毁,即@PreDestroy
- 其次DisposableBean接口销毁
- 最后destroyMethod销毁( 包括自定义名称,推断名称,AutoCloseable 接口多选一)
总结
- 阶段1:处理名称,检查缓存(处理别名,看看缓存里有没有,有就直接返回,没有再执行后续流程.)
- 阶段2:检查父工厂(当前bean名字在缓存里没有找到,会去找对应的父工厂)
- 阶段3:检查DependsOn(检查依赖关系,先创建DependsOn后面的bean)
- 阶段4:按Scope创建bean
①创建singleton
②创建 prototype
③创建其它 scope - 阶段5:创建bean
①创建 bean实例- @Autowired,唯一带参构造, 默认构造(优先采用注解@Autowired)
②依赖注入 - @Autowired @Value(AutowiredBeanPostProcessor后置处理器处理这两个注解), @Resource(CommonAnnotationBeanPostProcessor后置处理器处理这个注解), ByName ByType(根据名字匹配还是根据类型匹配),精确指定
(优先级: 精确指定 > 根据名字或者类型匹配 > 注解)
③初始化- Aware接口处理,@PostConstruct, InitializingBean, initMethod
(优先级:从前到后依次降低)
④登记可销毁 bean - 阶段6:类型转换
这两个注解), @Resource(CommonAnnotationBeanPostProcessor后置处理器处理这个注解), ByName ByType(根据名字匹配还是根据类型匹配),精确指定
(优先级: 精确指定 > 根据名字或者类型匹配 > 注解)
③初始化- Aware接口处理,@PostConstruct, InitializingBean, initMethod
(优先级:从前到后依次降低)
④登记可销毁 bean
- 阶段6:类型转换
- 阶段7:销毁bean