引言
场景
Object A/Object B
A成员属性离包含B,B成员属性里包含A
梳理B和A在注入Spring容器中做了什么事
来一张清晰的Spring创建Bean的流程图吧
Bean的创建最为核心三个方法解释:
- createBeanInstance:例化,其实也就是调用对象的构造方法实例化对象
- populateBean:填充属性,这一步主要是对bean的依赖属性进行注入(@Autowired)
- initializeBean:回到一些形如initMethod、InitializingBean等方法
实例化和初始化
读此文前应当先分清实例化和初始化的概念
实例化:@xxxxxx的地址,value=null
初始化:@xxxxxx的地址,value=xxx
Spring启动一系列操作方法
refresh()
以下使用Spring Boot version2.x进行演示
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
其中里面调用了11个方法,分别负责刷新/创建/启动等一系列操作
this.prepareRefresh();
做容器刷新前的准备工作1. 设置容器的启动时间2. 设置活跃状态为true3. 设置关闭状态为false4. 获取Environment对象, 并加载当前系统的属性值到Environment对象中5. 准备监听器和事件的集合对象, 默认为空的集合
**ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
**
创建容器对象: DefaultListavleBeanFactory加载XML配置文件的属性值到当前工厂中, 最重要的就是BeanDefinition
this.prepareBeanFactory(beanFactory);
beanFactory的准备工作, 对各种属性进行填充
this.postProcessBeanFactory(beanFactory);
子类覆盖方法做额外的处理, 此处我们自己一般不做任何扩展工作, 但是可以查看web中的代码是有具体实现的
this.invokeBeanFactoryPostProcessors(beanFactory);
调用各种beanFactory处理器
this.registerBeanPostProcessors(beanFactory);
注册bean处理器, 这里只是注册功能, 真正调用的是getBean()方法
this.initMessageSource();
为上下文初始化message源, 即不同语言的消息体, 国际化处理
this.initApplicationEventMulticaster();
初始化事件监听多路广播器
this.onRefresh();
留给子类来初始化其他的bean
this.registerListeners();
在所有注册的bean中查找listener bean, 注册到消息广播器中
this.finishBeanFactoryInitialization(beanFactory);
初始化剩下的单实例(非懒加载的)
this.finishRefresh();
完成刷新过程, 通知生命周期处理器lifecycleProcessor刷新过程, 同时发出ContextRefreshEvent通知别人
理论分析
Spring解决循环依赖是采用Spring三级缓存实现的
以下为Spring Boot的三级缓存
我们可以看到在DefaultSingletonBeanRegistry类里面的三个Map
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
singletonObjects为一级缓存,我们实例化的bean都在这个map里,侠义的说singletonObjects才是我们真正的spring容器,存放bean的地方。
earlySingletonObjects为二级缓存,是存放未完成的bean的缓存,如果有代理的话,存放的是代理对象。
singletonFactories为三级缓存,存放的是一个ObjectFactory,ObjectFactory是一个函数式接口,里面只有一个getObject()方法,数据通过getObject方法获得。
在获取bean时候三级缓存的使用的源码
AbstractBeanFactory类的关键方法
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
// 从三级缓存中获取
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isTraceEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 代码省略。。。。。。。。。。。。。。。。。。。。
}
DefaultSingletonBeanRegistry类的关键方法
@Nullable
public Object getSingleton(String beanName) {
return this.getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
// 从一级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) {
// 从二级缓存中获取
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject =
//从三级缓存获取
this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
方式:
- A实例化结束,开始实例化获取B成员属性,从三级缓存中获取
- 如果三级缓存中没有B对象,那么就会去实例化B,加入到三级缓存中
- 然后流程是初始化B(当前只是介绍了A对象只有一个成员变量,有别的成员变量也是这一步流程,直至所有成员变量都初始化完毕,最后才能回到一开始的目的:初始化A,不要在看源码的时候被绕晕了)
- B初始化需要A属性就从三级缓存中直接获取到实例化好的A,将B从三级缓存中移除放入一级缓存,B就是初始化好的状态了
- 当所有成员变量都初始化好后再回到起点把A实例再走一遍getSingleton方法(这时在一级缓存中就可以获取到所有成员属性),完成A的初始化
- 将A添加到一级缓存中,三级缓存的A就被移除,这样就完成了A对象的初始化,到创建B对象的时候一级缓存直接获取到对象A
精细梳理:
A实例化 -> doGetBean()获取bean -> getSingleton()实例化之前beanName加入到singletonsCurrentlyInCreation中 -> createBean()实例化Bean完成之后加入到三级缓存中 -> populateBean()填充被注入的B -> 实例化B -> 和A流程一样 -> populateBean()填充被注入的A -> doGetBean()从三级缓存中获取 -> B初始化完成 -> 回到原点初始化A -> A初始化完成
大功告成,自己阅源吗后理解,错误地方望指出,欢迎监督
populateBean填充bean属性代码块鉴赏
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 封装bean的对象为空,则进行一些处理和验证
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
boolean continueWithPropertyPopulation = true;
// 看代码逻辑应该是可以实现InstantiationAwareBeanPostProcessor
// 自定义去实现注入属性的逻辑,这样就不用再去走spring自己的方式去查找需要注入的bean
// 和注入方式了
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 根据名称注入还是根据类型注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根据名称注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根据类型注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// java自省,找到那些自省规范的属性,然后排除掉spring忽略的
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 根据注解注入
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
// 将属性应用到bean上
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
populateBean是查找bean中的属性,找到需要注入的属性。然后设置到bean上。来梳理下populateBean的流程。
- 检查包装bean的包装对象是不是空,是空话判断是不是有需要注入的属性,如果有则抛出异常,没有则返回。
- 接下来查找实现InstantiationAwareBeanPostProcessor的BeanPostProcessor,调用实例化之后的后置方法。如果返回false,则不会再走spring自己的属性配置。这个应该是留给需要自定义装配的。在SpringBoot源码中,我暂时没有看到返回false的BeanPostProcessor。按照我自己的想法,如果自己去实现属性的装配,去实现InstantiationAwareBeanPostProcessor就可以了。
- 根据配置的模式来判断是根据类型注入还是根据名称装配。其实我们一般使用springBoot的时候,这里默认是手动装配。
- java自省,获取那些符合自省的属性
- InstantiationAwareBeanPostProcessor的BeanPostProcessor会根据注解查找需要装配的bean
- 如果属性配置的值不为空,将配置的属性应用到bean上
populateBean大体的逻辑就是这样,对应上面对象A在来说下,也就是要到第5步时候,根据去BeanPostProcessor查找需要装配的Bean了。对于@Autowired注解,对应的是AutowiredAnnotationBeanPostProcessor。
创建Bean的时候,三级缓存应用鉴赏
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 代码省略。。。。。。。。。。。。。。。。。。。。
// 三级缓存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 代码省略。。。。。。。。。。。。。。。。。。。。
return exposedObject;
}
入三级缓存代码鉴赏
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized(this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 添加到三级缓存
this.singletonFactories.put(beanName, singletonFactory);、
// 删除二级缓存
this.earlySingletonObjects.remove(beanName);
// 加入注册bean的set中
this.registeredSingletons.add(beanName);
}
}
}
警告
看到do开头的方法要拍拍脸,大概率到了绕圈的地方了,保持清醒别被绕晕了
注入方式
有三种方式注入导致的循环依赖问题
field注入,set方法注入还有构造器方法注入
Spring采用三级缓存解决的是set方式注入导致的循环依赖问题,不能解决构造器注入导致循环依赖的问题
构造器注入构成的循环依赖,此种循环依赖方式是没法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。这也是构造器注入的最大劣势(它有不少独特的优点)
后置处理
后期讲吧,你一下也消化不了,面试暂时没啥人问到这个,生命周期也会有这个,了解下就可以
Bean的生命周期
Spring源码中有明确的说明SpringBean的生命周期
如图:
文本阐述一下
1.启动spring容器,也就是创建beanFactory(bean工厂),一般用的是beanFactory的子类applicationContext, applicationContext比一般的beanFactory要多很多功能,比如aop、事件等。通过applicationContext加载配置文件,或者利用注解的方式扫描将bean的配置信息加载到spring容器里面。
2.加载之后,Spring容器会将这些配置信息(java bean的信息),封装成BeanDefinition对象BeanDefinition对象其实就是普通java对象之上再封装一层,赋予一些spring框架需要用到的属性,比如是否单例,是否懒加载等等。
3.然后将这些BeanDefinition对象以key为beanName,值为BeanDefinition对象的形式存入到一个map里面,将这个map传入到spring beanFactory去进行springBean的实例化。
4.传入到pring beanFactory之后,利用BeanFactoryPostProcessor接口这个扩展点去对BeanDefinition对象进行一些属性修改。
5.开始循环BeanDefinition对象进行springBean的实例化,springBean的实例化也就是执行bean的构造方法(单例的Bean放入单例池中,但是此刻还未初始化),在执行实例化的前后,可以通过InstantiationAwareBeanPostProcessor扩展点 (作用于所有bean)进行一些修改。
6.spring bean实例化之后,就开始注入属性,首先注入自定义的属性,比如标注@autowrite的这些属性,再调用各种Aware接口扩展方法,注入属性(spring特有的属性), 比如BeanNameAware.setBeanName,设置Bean的ID或者Name;
7.初始化bean,对各项属性赋初始化值,初始化前后执行BeanPostProcessor
(作用于所有bean)扩展点方法,对bean进行修改。
初始化前后除了BeanPostProcessor扩展点还有其他的扩展点,执行顺序如下:
(1). 初始化前 postProcessBeforeInitialization()
(2). 执行构造方法之后 执行 @PostConstruct 的方法
(3). 所有属性赋初始化值之后 afterPropertiesSet()
(4). 初始化时 配置文件中指定的 init-method 方法
(5). 初始化后 postProcessAfterInitialization()
先执行BeanPostProcessor扩展点的前置方法postProcessBeforeInitialization(),
再执行bean本身的构造方法
再执行@PostConstruct标注的方法
所有属性赋值完成之后执行afterPropertiesSet()
然后执行 配置文件或注解中指定的 init-method 方法
最后执行BeanPostProcessor扩展点的后置方法postProcessAfterInitialization()
8.此时已完成bean的初始化,在程序中就可以通过spring容器拿到这些初始化好的bean。
9.随着容器销毁,springbean也会销毁,销毁前后也有一系列的扩展点。
销毁bean之前,执行@PreDestroy 的方法销毁时,执行配置文件或注解中指定的 destroy-method 方法。
以上就是spring bean的整个生命周期
其实就是根据配置文件或注解信息,生成BeanDefinition,
循环BeanDefinition去实例化->注入属性->初始化->销毁,在这4个阶段执行前后,Spring框架提供了一系列的扩展点。
SpringBean的扩展点
(1)、容器级扩展点(作用于所有bean):
BeanFactoryPostProcessor接口:
在循环初始化springbean之前,对BeanDefinition元数据做扩展处理
InstantiationAwareBeanPostProcessor接口:
在对象实例化前后扩展,作用于所有bean
BeanPostProcessor接口:
在对象初始化化前后扩展,作用于所有bean
(2)、Bean扩展点(作用于单个bean):
Aware接口:
springBean实例化并且注入自定义属性之后
InitializingBean接口:
springBean初始化时,执行构造方法结束,并且属性赋初始化值结束之后执行
DiposableBean接口:
springBean销毁之前执行。
(3)、Bean自身的方法
包括了Bean本身调用的方法
通过配置文件中<bean>的init-method和destroy-method指定的方法(或者用注解的方式)
(4)、包括了AspectJWeavingEnabler,
ConfigurationClassPostProcessor,
CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。
工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。