目录
SpringBean的生命周期
Bean实例属性填充
三级缓存
常用的Aware接口
Spring IoC容器实例化Bean总结
SpringBean的生命周期
Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:
- Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton,是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;
- Bean的初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,Spring的注解功能等。以及Bean的循环引用问题都是在这个阶段体现的。
- Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去。即完成了Spring Bean的整个生命周期。
接下来我们着重于Bean的初始化阶段进行分析,初始化过程涉及如下几个过程:
- Bean实例的属性填充
- Aware接口属性注入
- BeanPostProcessor的before()方法回调
- InitializingBean接口的初始化方法回调
- 自定义初始化方法inti回调
- BeanPostProcessor的after()方法回调
Bean实例属性填充
基于xml文件的实例属性填充。
<bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property><property name="name" value="张三"></property>
</bean>
在属性注入中,存在三种情况:
- 一种基本属性注入,通过反射拿到set方法直接注入
- 一种单项引用属性注入,如UserService中需要注入UserDao,但UserDao不需要UserService,这种从容器中执行getBean方法后通过set方法反射进去,如果容器中不存在,则先创建被注入的对象后再进行诸如操作。
- 一种双向对象属性注入,也就是说,UserService中需要注入UserDao,UserDao需要注入UserService。这涉及到循环引用。
下面是循环引用的问题流程图
如果循环依赖的话,半成品的bean会被存储在内存中,不归Spring管控,那么在注入时,就无法从容器中获取到对应的bean,从而导致死循环不停的创建对象。解决方法是,在Spring中添加一个存储半成品bean的map,当无法从单例池中获取的对象时,从半成品中的map获取
三级缓存
所谓三级缓存,分别是单例池与两个存储半成品bean的map集合,在源码中为
这三个Map集合,分别存储的是:
- 实例化与初始化都完成的bean,称为一级缓存
- 缓存半成品,且对象已经被其他对象引用了,称为二级缓存
- 缓存半成品,对象也未被引用,使用时在通过工厂创建bean,称为三级缓存
UserService和UserDao循环依赖的过程结合上述三级缓存描述一下就是
- UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;
- UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
- UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;
- UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存;
- UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
- UserService 注入UserDao;
- UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存。
常用的Aware接口
Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象。
Aware接口 | 回调方法 | 作用 |
ServletContextAware | setServletContext(ServletContext context) | Spring框架回调方法注入ServletContext,web环境下才生效 |
BeanFactoryAware | setBeanFactory(BeanFactory factory) | Spring框架回调方法注入beanFactory对象 |
BeanNameAware | setBeanName(String beanName) | Spring框架回调方法注入当前Bean在容器中的beanName |
ApplicationContextAware | setApplicationContext(Application application) | Spring框架回调方法注入ApplicationContext对象 |