spring源码阅读与分析——循环依赖(附图解)

目录

一、概要

二、方法调用过程分析

三、源码分析

3.1 准备工作

3.2 refresh()

3.3 finishBeanFactoryInitialization()

3.4 preInstantiateSingletons()

3.5 getBean()

3.6 doGetBean()

3.7 第2次调用getSingleton()创建对象

3.8 createBean()

3.9 doCreateBean()

3.10 populateBean()

3.10.1 getBean()-获取属性B b

3.10.2 同上实例化A一样的步骤实例化B

3.10.3 第1次getSingleton中获取a对象

3.11 完成属性注入

3.12 initializeBean()

3.13 将创建好的bean put到单例池中

3.14 将完整的B类bean返回给A注入属性b

3.15 初始化A类bean、将其put到单例池中


说明:此次分析是基于spring 5.1.x 版本

一、概要

spring创建bean本质上还是对象的创建,而创建一个完整的对象包含了两部分:1、实例化对象 2、实例化对象属性。

在spring中,对象的实例化通过反射方式实现,对象属性则是在实例化对象之后通过BeanPostProcessor(后置处理器)完成属性的注入。

spring在默认单例的情况下支持循环引用。循环依赖的主要思想是:spring在创建bean时不等bean创建完成就需要将该bean对应的ObjectFactory曝光(将ObjectFactory加入缓存),以便下一个bean需要依赖上个bean时就直接在缓存中取到上个bean对应的ObjectFactory而拿到该“半成品”bean,这样就克服了需要某个bean时重新创建bean导致无限递归创建bean。其实现过程主要是通过标记bean创建状态和多级缓存的方式解决。(能这样解决也得益于可以传递引用)

举个实在的栗子吧:

对于循环依赖的对象:如A类依赖B类,B类依赖A类那么在创建过程中,比如先创建A类bean那么在进行A类bean的属性注入时就去获取B类bean作为自己的属性。此时结果发现还没创建B类bean,但目前又急需B类bean呀,怎么办,那就准备创建B类bean呗。创建B类bean过程中进行属性注入时又发现需要A类bean作为自己的属性,于是乎就尝试获取A类bean,结果发现A类bean也没创建完,因为A类bean还在等B类bean创建好了把完整的B类bean返给它,它才能完成创建。到了这儿,A类bean是个半成品,正在等待B类bean创建完了将B类bean给它;而B类bean也是半成品,正在尝试获取A类bean。注意此时A类bean只创建了部分,B类bean来获取时就暂时把不完整的A类bean先给B用着,B完成属性注入之后再创建A类bean。注意B类bean里面的a属性还没实例化(A类bean还是个半成品),但因为这里记录的引用,当A类bean创建完了之后这儿自然也就连起来了。

AB类循环依赖注入属性流程如下:

先对这个过程有了些理解后再来看源码就会清晰很多,上面提到的“成品”对象和“半成品”对象在spring中是用该对象“是否正在创建”来标识,正在创建过程的bean为“半成品”、已完成创建的bean为“成品”。

 

如下两个类相互循环依赖,本文将以此来探讨spring解决循环依赖的方式。

package pers.whz.spring.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {
	@Autowired
	B b;

	public A() {
		System.out.println("create A");
	}

}
package pers.whz.spring.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class B {
	@Autowired
	A a;

	public B() {
		System.out.println("create B");
	}
}

二、方法调用过程分析

 

三、源码分析

3.1 准备工作

在建立了上面两个相互依赖的A类和B类之后,再创建一个配置类和测试类,如下:

package pers.whz.spring.test;

import org.springframework.context.annotation.ComponentScan;

// 配置类:作用是把这个包下的类扫描到
@ComponentScan("pers.whz.spring")
public class Appconfig {
}
package pers.whz.spring.test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
	public static void main(String[] args) {
                // spring启动,看源码入口
		AnnotationConfigApplicationContext annotationConfigApplicationContext
				= new AnnotationConfigApplicationContext(Appconfig.class);
	}
}

3.2 refresh()

该方法可以说是spring观码入口,spring最核心的部分就从这儿开始的。

3.3 finishBeanFactoryInitialization()

进入refresh()主体,定位到finishBeanFactoryInitialization()

这句的作用是:将注册到spring IOC容器中的类实例化。在此之前已经对加了配置的类扫描到,封装成BeanDefinition,并将其注册到了IOC容器中。

3.4 preInstantiateSingletons()

进入finishBeanFactoryInitialization()主体,定位到beanFactory.preInstantiateSingleton()

这句作用是:实例化所有非懒加载的单例类。(部分spring框架自身配置的类会提前实例化)

    public void preInstantiateSingletons() throws BeansException {
		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 记录所有bean的名字,可能(lazy、scope不需要实例化)需要去实例化的class
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 触发所有非延迟加载单例化beans的初始化,主要步骤为调用getBean
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 排除部分不需要实例化的类
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					// ……
				}
				else {
					// !!!尝试获取bean,获取不到就创建(实例化扫描出的类)
					getBean(beanName);
				}
			}
		}
		// Trigger post-initialization callback for all applicable beans...
    }

3.5 getBean()

进入preInstantiateSingleton()主体,定位到getBean()

这句作用是:获取bean,但实际上是尝试获得bean,获取不到就创建bean。进入getBean()主体,可以看到其实getBean(name)是个空壳,它通过这种方式来调用doGetBean()。

	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

3.6 doGetBean()

这个方法非常非常非常重要,它作用主要是向 IOC容器获取 bean,也是触发 DI 的地方。当然这儿虽然说的是获取bean,但如果获取不到bean呢?它就会创建bean。

里面有两个非常重要的getSingleton()方法, 第1个getSingleton()主要就是从缓存中取数据即向IOC容器获取bean,而 第2个getSingleton()就是创建bean以及触发DI,这两个方法后面会重点阐述。

 

	// 向 IOC容器获取 bean,也是触发 DI 的地方*****非常重要
	@SuppressWarnings("unchecked")
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		// 转化别名(alias)或bean名字,防止乱码、验证是否符合规则、转换别名、移除特殊符号(&)等
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		/*	!!!第1次调用 getSingleton()
		由 beanName 查看缓存(依次在一级二级三级缓存中找)中是否有已实例化的对象
		二三级缓存就是为解决循环引用而设计的
		此getSingleton()调用爷类DefaultSingletonBeanRegistry中的方法,默认支持循环引用
		 */
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			/*获取给定 bean 的实例对象,主要是完成 FactoryBean 的相关处理
                        注意:FactoryBean 是IOC容器中一种特殊的bean,它能实例化bean对象
            	             BeanFactory 是一个IOC容器,它保存了 bean 的基本配置信息
			 */
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		// 缓存中没有找到该beanName的对象,准备创建该对象
		else {
				// Create bean instance.
				// 第一次getSingleton()返回值为空才执行到这儿,这儿的目标对象都是单例的
				if (mbd.isSingleton()) {
					/* !!!第2次调用 getSingleton() 尝试创建目标对象,并注入所依赖的属性
					会把当前正在创建的类记录到set集合中,然后反射创建这个类实例并走完生命周期
					 */
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 完成目标对象的创建,若有代理也会在这儿完成
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// ……
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
			}
		}
		return (T) bean;
	}

3.7 第2次调用getSingleton()创建对象

进入doGetBean()主体,定位到第2次调用getSingleton()

这句作用是:创建bean对象,并注入该对象所依赖的属性。

如上面提到的,若是创建新的bean,那么就在第1次getSingleton()获取到的就为空,重点主要在第2次getSingleton()

需要注意lambda表达式有惰性求值的特性,createBean(beanName, mbd, args)返回的singletonFactory值在getSingleton中调用时才会执行这个createBean,不会先执行createBean再进入getSingleton。这个会涉及到在什么时候标记该对象正在创建过程,如果没注意到这点会以为先创建对象再标记在创建过程中这个错误,则会导致后面好几个地方理解不到。

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				/* !!!将beanName添加到singletonsCurrentlyInCreation这个set集合中
				表示beanName对应的bean正在创建中*/
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				try {
					/* !!!真正的创建bean,创建对象,但创建出的是代理对象
					先创建原对象,再创建代理对象*/
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// ……
				}
				finally {
					// ……
					// 创建完了bean之后,移除该bean正在创建的标记
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// !!!将创建的bean添加到单例池中
					addSingleton(beanName, singletonObject);
				}
			}
                }
	    return singletonObject;
	}

3.8 createBean()

该方法中主要要注意到doCreateBean(),这个是真正实例化对象的地方。

    	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
		// Prepare method overrides.
		// 处理lookup-method和replace-method配置,解决循环依赖一些问题
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
                            // ……
		}

		try {
			// bean后置处理器返回代理实例
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
                        // ……
		}

		try {
                            // !!!真正实例化对象
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// ……
		}

	}

3.9 doCreateBean()

这个方法主要就是完成对象的创建以及对象属性的注入工作。主要内容如下:

  1. 通过反射实例化对象。
  2. 判断是否允许循环依赖、是否单例、是否正在创建中这些条件,将目前创建的不完整的bean对应的ObjectFactory放在singletonFactories(存放bean工厂对象)中。!!!解决循环依赖的关键思想
  3. 完成属性的注入。
  4. 完成aop代理、bean执行生命周期的一些回调工作、aware回调等。

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		if (instanceWrapper == null) {
			// !!!反射方式new obj:推断构造方法
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					// 处理合并后的beanDefinition
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
                                // ……
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			// !!!若支持循环依赖,提前暴露一个工厂(将对象放入三级缓存中)
			// 第1次getSingleton()可以取到
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// !!!判断属性注入是否需要,继而完成属性注入
			populateBean(beanName, mbd, instanceWrapper);
			// !!!初始化bean、aware回调、aop代理
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
                            // ……
		}

		return exposedObject;
	}

3.10 populateBean()

这个方法里面进行对象属性的注入,通过后置处理器来进行的属性注入,当然针对不同的注入方式,如通过名字注入或者类型注入有不同的处理方式。

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
                   // ……
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		// !判断是否自动注入,处理不同属性注入方式
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			// !!!通过 BeanPostProcessor 完成属性注入,for执行完后属性注入完成
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
	}

3.10.1 getBean()-获取属性B b

在进行属性注入时,用getBean()获取bean,如果在缓存中获取不到bean,那么就马上创建bean。

目前这儿情况是正在创建A类bean,获取B类bean作为属性注入。

3.10.2 同上实例化A一样的步骤实例化B

获取B类bean过程中,却发现缓存中没找到。那么就准备创建B类bean,同上所述方式创建B类bean。

3.10.3 第1次getSingleton中获取a对象

在创建B类bean过程中,对B类bean注入属性时去获取A类bean。这个时候因为A类bean可以在三级缓存中获取到,所以在第1个getSingleton()时就拿到了缓存中存的A类bean半成品,此时A类bean还有个动作是将其由三级缓存提到二级缓存中,并将三级缓存中的A类bean清除。

3.11 完成属性注入

B类bean创建时获取到需要作为属性注入的A类bean半成品之后就完成了B类bean属性的注入。

3.12 initializeBean()

该方法里面主要完成AOP代理、bean执行生命周期的一些回调工作、aware回调等。

3.13 将创建好的bean put到单例池中

完成bean的创建之后,就将创建好的bean放到单例池中,也就是一级缓存里面,获取bean时直接取一级缓存中获取就可以了。

3.14 将完整的B类bean返回给A注入属性b

完成了B类bean的创建之后,就将完整的B类bean返回给A类bean作为属性注入。A类bean可直接在一级缓存中拿到完整的B类bean。对于设计的这三级缓存,一级缓存即单例池,存放bean对象的地方;二级缓存,存放不完整的bean,解决循环依赖的;三级缓存,存放单例bean工厂。

3.15 初始化A类bean、将其put到单例池中

最后完成了A类bean的创建之后,就将其放入单例池中,整个循环依赖注入主要过程也就结束了。

参考:

  1. spring源码 5.1.x;
  2. https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html
  3. https://blog.csdn.net/java_lyvee/article/details/101793774

本篇文章是本人学习过程中看了很多相关资料之后再按照我自己的理解认识表达出来的,若有理解有误,或者描述不当之处烦请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值