逻辑控-追Spring循环依赖源码后梳理-附带bean生命周期说明

引言

追源码后梳理流程

给某个小傻瓜

场景

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;
    }

方式:

  1. A实例化结束,开始实例化获取B成员属性,从三级缓存中获取
  2. 如果三级缓存中没有B对象,那么就会去实例化B,加入到三级缓存中
  3. 然后流程是初始化B(当前只是介绍了A对象只有一个成员变量,有别的成员变量也是这一步流程,直至所有成员变量都初始化完毕,最后才能回到一开始的目的:初始化A,不要在看源码的时候被绕晕了)
  4. B初始化需要A属性就从三级缓存中直接获取到实例化好的A,将B从三级缓存中移除放入一级缓存,B就是初始化好的状态了
  5. 当所有成员变量都初始化好后再回到起点把A实例再走一遍getSingleton方法(这时在一级缓存中就可以获取到所有成员属性),完成A的初始化
  6. 将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的流程。

  1. 检查包装bean的包装对象是不是空,是空话判断是不是有需要注入的属性,如果有则抛出异常,没有则返回。
  2. 接下来查找实现InstantiationAwareBeanPostProcessor的BeanPostProcessor,调用实例化之后的后置方法。如果返回false,则不会再走spring自己的属性配置。这个应该是留给需要自定义装配的。在SpringBoot源码中,我暂时没有看到返回false的BeanPostProcessor。按照我自己的想法,如果自己去实现属性的装配,去实现InstantiationAwareBeanPostProcessor就可以了。
  3. 根据配置的模式来判断是根据类型注入还是根据名称装配。其实我们一般使用springBoot的时候,这里默认是手动装配。
  4. java自省,获取那些符合自省的属性
  5. InstantiationAwareBeanPostProcessor的BeanPostProcessor会根据注解查找需要装配的bean
  6. 如果属性配置的值不为空,将配置的属性应用到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等等非常有用的工厂后处理器接口的方法。
 工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值