从一个小例子说一下spring中bean的创建流程
示例:A依赖B; B依赖A
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
上面演示的例子就是循环注入
如果改为多例的化,运行时就会报错,循环引用异常,找不到对象
@Scope(“prototype”)
Spring中的循环依赖问题在单例的情况下,Spring是已经帮我们解决好了,多例没有解决循环依赖问题。
为啥,多例的情况下 Spring没有去解决循环依赖问题?
因为在多例的情况下,设置的多例的对象没有明确哪一个,就会产生循环依赖问题。
SpringBean循环依赖三级缓存概念
思考问题:单例对象在什么时候创建?
在IOC容器被创建的时候创建
多例的情况下,是在getbean()调用的情况下创建。多例对象每次用完就会去销毁掉。
SpringBean Aservice对象被创建流程步骤源码分析
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
A bean = context.getBean(A.class);
}
35行点进去
synchronized (this.startupShutdownMonitor) {
// 容器预先准备,记录容器启动时间和进行标记状态
prepareRefresh();
// 创建BeanFactory。如果已经存在该工厂,那么销毁其里面的beans和自行关闭。如果没有,则创建工厂,并且进行装载BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置BeanFactory的上下文,比如classLoader和BeanPostProcessor,注册一些需要解决的依赖和需要忽略的依赖、注册涉及容器系统环境的bean等等。
prepareBeanFactory(beanFactory);
try {
// 模板方法,在BeanDefinition被装载后(所有BeanDefinition被加载,但是没有bean被实例化),提供一个修改beanFactory容器的入口。
postProcessBeanFactory(beanFactory);
// 在Bean未开始实例之前,提供BeanDefinition修改或者注册的入口。我们熟悉的PropertyPlaceHolderConfigurer就是在这里调用的。
invokeBeanFactoryPostProcessors(beanFactory);
//用于拦截Bean创建的BeanPostProcessor。
registerBeanPostProcessors(beanFactory);
// 初始化容器所需要的MessageSource,用于国际化处理
initMessageSource();
// 初始化容器的事件广播器。
initApplicationEventMulticaster();
// 模板方法
onRefresh();
// 注册监听器
registerListeners();
// 完成容器的初始化,里面会调用preInstantiateSingletons()完成单例对象的创建。
finishBeanFactoryInitialization(beanFactory);
// 完成上下文的刷新工作
finishRefresh();
}
AbstractApplicationContext类
这里重点介绍finishBeanFactoryInitialization方法,878行点进去
DefaultListableBeanFactory类
获取bean,882行点进去
AbstractBeanFactory类
202行点进去
AbstractBeanFactory类
这里说一下第一次调用这个方法时,取到的对象都是空的,直接返回。
第二次调用时在看这吧,要不然会弄晕
第二次调用时会先从一级缓存获取bean获取,没取到,
判断这个bean是不是正在创建中(getSingleton的重载方法处理过了,后面会说),是的话从二级缓存中去取,取不到的话判断是否允许循环依赖,允许的话,会去三级缓存中去获取。取到了返回这个bean,
现在返回到调用这个方法的类里面(AbstractBeanFactory.java)
326行点进去
这个getSingleton重载方法大家可以点进去,看到有个beforeSingletonCreation(beanName)方法,这个方法的作用就是
将bean加进singletonsCurrentlyInCreation(set集合),标记这个bean正在创建中
329行点进去
AbstractAutowireCapableBeanFactory类
518行点进去
AbstractAutowireCapableBeanFactory类
600行是对象进行属性赋值的地方。先看前面585行的addSingletonFactory方法
addSingletonFactory方法很有用,点进去
DefaultSingletonBeanRegistry类
这里记录一下,循环依赖时,创建A对象时先将自己曝光出去,先放进三级缓存(addSingletonFactory方法),同时删除二级缓存,在populateBean方法中会发现引用了B对象,然后创建B对象,B对象执行创建流程,B对象发现自己依赖A对象,又会去执行创建A对象的流程,这里就会第二次执行getSingleton方法了,在这个方法里肯定能找到
在三级缓存中的A对象(此时A对象还没有进行属性赋值,是个不完全的对象),然后将三级缓存对象赋值给一级缓存并放进二级缓存中,同时删除三级缓存中的A对象,然后将A对象注入自己,并走完后面的创建bean的流程,这时B对象已经是一个完全的对象了,回到A对象的populateBean的方法中(这时候B对象创建完成注入到A对象中),A对象此时还没有执行完populateBean方法,A对象执行属性赋值以及后面的初始化动作(个人理解)
AbstractAutowireCapableBeanFactory类
执行完600行的populateBean方法(这里就是上面说的,进行属性赋值),然后执行601行的initializeBean方法
总结一下bean的创建流程,创建bean时,先从缓存中找,有就返回这个bean,没有就创建用BeanWrapper包装一下(初始化但还没有值),
然后populateBean方法进行属性赋值,initializeBean方法执行对象初始化前的一些操作,先判断这个bean有没有实现某个Aware,将Aware放进去,Aware主要作用是将bean跟spring容器联系起来,要不然老认为Aware是无意识的,然后执行这个bean的前置处理器,如果实现了InitializingBean接口在这里调用一下,执行这个bean的后置处理器,
然后放到单例缓存池中,后面会执行这个bean的销毁方法…