作者:Java3y
链接:www.zhihu.com/question/36…
来源:知乎
基于知乎文章修修改改
java管理Bean
普通Java对象和Spring所管理的Bean实例化的过程是有些区别的。
在普通Java环境下创建对象简要的步骤可以分为:
- java源码被编译为被编译为class文件
- 等到类需要被初始化时(比如说new、反射等)
- class文件被虚拟机通过类加载器加载到JVM
- 初始化对象供使用
可以理解为它是用Class对象作为「模板」进而创建出具体的实例
Spring管理Bean
BeanDefinition元数据管理
Spring有BeanDefinition来存储我们给Spring Bean定义的元数据)@Scope、@Lazy、@DependsOn等等)
Spring除了Class对象之外,还会使用BeanDefinition的实例来描述对象的信息。
比如说可以在Spring所管理的Bean有一系列的描述:@Scope、@Lazy、@DependsOn等。
可以理解为:Class只描述了类的信息,而BeanDefinition描述了对象的信息
Spring在启动的时候需要「扫描」在XML/注解/JavaConfig 中需要被Spring管理的Bean信息
随后,会将这些信息封装成BeanDefinition,最后会把这些信息放到一个beanDefinitionMap中
这个Map的key是beanName,value是BeanDefinition对象
到这里就是把定义的元数据加载起来,目前真实对象还没实例化
接着会遍历这个beanDefinitionMap,执行BeanFactoryPostProcessor这个Bean工厂后置处理器的逻辑
比如定义的占位符信息,就是通过BeanFactoryPostProcessor的子类PropertyPlaceholderConfigurer进行注入进去
也可以自定义BeanFactoryPostProcessor来对定义好的Bean元数据进行获取或者修改(场景少)
实例化对象
BeanFactoryPostProcessor后置处理器执行完了以后,就到了实例化对象
在Spring里边是通过反射来实现的,一般情况下会通过反射选择合适的构造器来把对象实例化
这里只是把对象给创建出来,而对象具体的属性还没注入。
依赖注入
实例化对象后就是依赖注入。
初始化
相关属性注入完之后,往下接着就是初始化的工作了。
首先判断该Bean是否实现了Aware相关的接口,如果存在则填充相关的资源
比如我希望通过代码程序的方式去获取指定的Spring Bean。会抽取成一个工具类,去实现ApplicationContextAware接口,来获取ApplicationContext对象进而获取Spring Bean
BeanPostProcessor后置处理器
Aware相关的接口处理完之后,就会到BeanPostProcessor后置处理器啦
BeanPostProcessor后置处理器有两个方法,一个是before,一个是after
BeanPostProcessor后置处理器是AOP实现的关键(关键子类AnnotationAwareAspectJAutoProxyCreator)。
所以,执行完Aware相关的接口就会执行BeanPostProcessor相关子类的before方法
BeanPostProcessor相关子类的before方法执行完,则执行init相关的方法,比如说@PostConstruct、实现了InitializingBean接口、定义的init-method方法。
被调用执行顺序:@PostConstruct、实现了InitializingBean接口以及init-method方法。
这些都是Spring给扩展
等到init方法执行完之后,就会执行BeanPostProcessor的after方法。
销毁
销毁的时候就看有没有配置相关的destroy方法,执行就完事了 #循环依赖 A对象依赖B对象,B又依赖A,这就是循环依赖。
对象属性的注入在对象实例化之后。它的大致过程是这样的:
- 首先A对象实例化,然后对属性进行注入,发现依赖B对象
- B对象此时还没创建出来,所以转头去实例化B对象
- B对象实例化之后,发现需要依赖A对象,那A对象已经实例化了嘛,所以B对象最终能完成创建
- B对象返回到A对象的属性注入的方法上,A对象最终完成创建
三级缓存&循环依赖&AOP
- singletonObjects(一级,日常实际获取Bean的地方)
- earlySingletonObjects(二级,还没进行属性注入的bean实例,由三级缓存放进来。如果又代理,则是beanProxy实例)
- singletonFactories(三级,Value是一个对象工厂)
- A对象实例化之后,属性注入之前,会把A对象放入三级缓存中。key是BeanName,Value是ObjectFactory
- A对象属性注入时,发现依赖B,又去实例化B时
- B属性注入需要去获取A对象,这里就是从三级缓存里拿出ObjectFactory,从ObjectFactory得到对应的Bean(就是对象A)
- 把三级缓存的A记录给干掉,然后放到二级缓存中。二级缓存存储的key是BeanName,value就是Bean(还没做完属性注入的Bean)
- 等到完全初始化之后,就会把二级缓存给remove掉,放到一级缓存中。 我们使用的bean是一级缓存的
为什么非要用三级缓存?
三级缓存(就是key是BeanName,Value为ObjectFactory)。
有可能A对象依赖的B对象是有AOP的(B对象需要代理)。
假设没有第三级缓存,第二级缓存(Value存对象,而不是工厂对象)。
在有AOP的情况下,就得在存入第二级缓存之前做AOP代理。
这里肯定是需要考虑代理的情况的,比如A对象是一个被AOP增量的对象,B依赖A时,得到的A肯定是代理对象。、
所以,三级缓存的Value是ObjectFactory,可以从里边拿到代理对象。
而二级缓存存在的必要就是为了性能,从三级缓存的工厂里创建出对象,再扔到二级缓存(这样就不用每次都要从工厂里拿)
总结
- 首先是Spring Bean的生命周期过程,Spring使用BeanDefinition来装载着我们给Bean定义的元数据
- 实例化Bean的时候遍历BeanDefinitionMap
- Spring的Bean实例化和属性赋值是分开两步来做的
在Spring Bean的生命周期,Spring预留了很多的hook给我们去扩展
- Bean实例化之前有BeanFactoryPostProcessor
- Bean实例化之后,初始化时,有相关的Aware接口供我们去拿到Context相关信息
- 环绕着初始化阶段,有BeanPostProcessor(AOP的关键)
- 在初始化阶段,有各种的init方法供我们去自定义
循环依赖的解决主要通过三级的缓存
- 在实例化后,会把放到三级缓存(此时的key是BeanName,Value是ObjectFactory)。
- 在注入属性时,发现需要依赖B,也会走B的实例化过程,B属性注入依赖A,从三级缓存找到A。
- 删掉三级缓存,放到二级缓存
关键源码方法
org.springframework.context.support.AbstractApplicationContext#refresh(入口)org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization(初始化单例对象入口)org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons(初始化单例对象入口)org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)(万恶之源,获取并创建Bean的入口)org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean(实际的获取并创建Bean的实现)org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)(从缓存中尝试获取)org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])(实例化Bean)org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean(实例化Bean具体实现)org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance(具体实例化过程)org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory(将实例化后的Bean添加到三级缓存)org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean(实例化后属性注入)org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)(初始化入口)