spring 源码阅读2:循环依赖1

spring源码阅读2: 循环依赖1


在上一篇文章中,我们分析了@Autowired 的主要注入过程。这一篇我们分析一下spring 是如何通过缓存解决spring 循环依赖的。在分析前先阐述一下本文中用到的两个词语的意思:

  • 实例化
    这里的实例化是指通过构造器创建出对象,也就是执行了源码一中的createBeanInstance方法。
  • 初始化
    这里的初始化时指执行了源码一种的populateBean和initializeBean方法。populateBean方法会处理@Autowired,@value注入、setter注入等。而initializeBean会处理Aware回调,例如ApplicationContextAware,自定义的初始化方法、InitializingBean回调等等。

什么是spring 循环依赖

假设有两个spring bean 如下:

@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
}

public class ServiceB {
    @Autowired
    private ServiceB serviceB;
}

假设是Service A 先创建,那么大概的创建流程如下:

  1. 通过无参构造器实例化出serviceA对象
  2. 处理serviceA的@Autowired,发现要注入ServiceB
  3. 去spring 容器中查找ServiceB对象
  4. 发现ServiceB 还没有创建
  5. 通过无参构造器实例化一个ServiceB对象
  6. 处理ServiceB的@Autowired,发现要注入serviceA
  7. 去spring 容器中查找ServiceA对象
  8. 发现ServiceA还没有创建,去创建ServiceA对象

从上面流程可以看出,如果不进行特殊的处理,就会陷入要创建ServiceA就要先创建ServiceB,要创建ServiceB就要先创建ServiceA的循环中。spring为了解决这种循环依赖的问题,在spring bean 创建的过程中增加了缓存。也就是在上面流程的第一步和第二步之间增加一步:先将实例化后的ServiceA对象保存到缓存中,那么当进行到第8步的时候,如果发现Service A还没初始化完成,就先从缓存中取出ServiceA的对象注入。具体流程见下面的源码分析

源码分析

源码一:AbstractAutowireCapableBeanFactory.doCreateBean()

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
		    // 返回spring bean实例,如果没有指定构造器或者工厂方法,通常就是简单的通过无参构造器返回一个对象。注意这时候返回的对象,所有的字段都还是默认值
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 这里返回来的就是实例化的spring bean
		Object bean = instanceWrapper.getWrappedInstance();
		// 省略部分代码
	
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 当允许循环依赖的时候,先将实例化的spring bean保存到缓存中,详情见源码2、源码3
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
		    // 会在这一步调用AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,处理@Autowire、@value等注入
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
       // 省略部分代码 
		return exposedObject;
	}

源码二:DefaultSingletonBeanRegistry.addSingletonFactory()

     // 缓存的初始化完成后的spring bean对象
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // 缓存对象对应的对象工厂,可以通过ObjectFactory.getObject()到对象
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
   // 缓存的早期的单例对象也就是刚刚实例化完成的对象
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    // 根据单例对象注册的顺序保存单例对象的beanName
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
		    // 如果singletonObjects没有包含对应的bean说明该bean还没有初始化完成。
			if (!this.singletonObjects.containsKey(beanName)) {
			    // 保存beanName对应的ObjectFactory,ObjectFactory是一个函数接口,提供了一个getObject()方法,返回对象,结合源码三,可以知道就是返回刚刚实例化完成的对象;
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

源码三、AbstractAutowireCapableBeanFactory.getEarlyBeanReference()

    // 通常而言,这个方法会之间返回传入的bean,在本文中也就是会返回刚刚实例化完成的bean对象,但是某些情况下可能会返回动态代理后的对象,例如当bean中存在@Transactional的时候,下篇文章会阐述这个问题
	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

上面分析了spring 缓存实例化后的spring bean的流程,下面我们通过分析依赖查找的源码,分析是如何获取这些缓存的对象的。

源码四:AbstractBeanFactory.doGetBean()

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		Object bean;

		// 查询是否有缓存的单例对象,详情见源码5
		Object sharedInstance = getSingleton(beanName);
		// 如果缓存中已经存在对象,那么进行一些判断处理后返回
		if (sharedInstance != null && args == null) {
		  // 省略部分代码
		}

		else {
			// 省略部分代码
			try {
               // 省略部分代码
            // 如果缓存中没有单例对象就先去创建对象(见源码一),然后将对象保存在缓存中(见源码6)
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
          // 省略部分代码
		return (T) bean;
	}

源码五:DefaultSingletonBeanRegistry.getSingleton()

   // 缓存的初始化完成后的spring bean对象
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // 缓存对象对应的对象工厂,可以通过ObjectFactory.getObject()到对象
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
   // 缓存的早期的单例对象也就是刚刚实例化的对象
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    // 根据单例对象注册的顺序保存单例对象的beanName
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	   // 先从singletonObjects中查询是否有初始化完成后的bean对象
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果没有初始化完成后的对象,同时对象正在创建中,则进入下面的流程
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				
				if (singletonObject == null && allowEarlyReference) {
				//如果允许循环依赖,那么就从singletonFactories中获取对象的ObjectFactory
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                     // 调用ObjectFactory.getObject()方法,获取到缓存的早期引用对象也就是刚刚实例化的对象
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

源码六:DefaultSingletonBeanRegistry.getSingleton()

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	           // 省略部分代码
				try {
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				// 省略部分代码
				if (newSingleton) {
				    // 将调用createBean()方法返回的对象(初始化完成后的对象)保存到singletonObjects中,
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

总结

在分析完源码后,我们重新调整一下ServiceA和ServiceB的流程

  1. 通过无参构造器实例化出serviceA对象
  2. 将实例化的ServiceA对象保存到缓存singletonFactories中
  3. 处理serviceA的@Autowired,发现要注入ServiceB
  4. 去spring 容器中查找ServiceB对象
  5. 发现ServiceB 还没有创建
  6. 通过无参构造器实例化一个ServiceB对象
  7. 处理ServiceB的@Autowired,发现要注入serviceA
  8. 去spring 容器中查找ServiceA对象
  9. 从singletonFactories中获取实例化的ServiceA对象,完成ServiceB的创建
  10. 完成ServiceB的创建后,就可以继续ServiceA对象的初始化

上面的流程就是spring 解决普通spring bean 循环依赖的的总体流程。但是对应一些需要动态代理的spring bean ,例如带有@Async注解的spring bean,我们常常会遇到 一个 BeanCurrentlyInCreationException 异常,然后类型下面的报文,下一篇文章我们分析这个异常产生的原因。

in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值