spring 循环依赖注入实现原理(源码分析)

结论

只有单例模式下的循环依赖才可以,其他模式会报错。

对循环依赖的简单介绍

A依赖B、B依赖A 形成一个依赖环。spring的解决方案是,实例化A,之后将A封装到一个ObjectFactory对象中存储。对A进行属性填充的时候,发现有B需要实例化,则去实例化B,实例化B的时候也会将B封装到一个ObjectFactory对象中存储。B实例化完之后,会去填充B的属性,这是发现有A属性需要填充,这是不再会去创建A而是从封装了A对象的ObjectFactory中直接取。从而完成B的属性填充,继而完成了A的属性填充。

源码分析

本次源码分析中案例是UrlServiceUrlService2相互依赖。系统首先实例化UrlService,再实例化UrlService2。仔细观察截图可见下面的截图有两次处理依赖处理。我们的本篇的原码也是以下图的方法压栈顺序依次分析。分析者需要有对spring的源码整体有一定的把握,可以参考我的另外两篇文章

在这里插入图片描述
下面进行代码分析篇。

	#AbstractBeanFactory 
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
			    ...省略
				// 创建bean的入口
				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
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	//省略
	singletonObject = singletonFactory.getObject(); //实际进入上个代码块的createBean(beanName, mbd, args)方法
	//省略
}
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
	//省略
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	//省略
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		//省略
		// Instantiate the bean.
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 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) {
			//为了解决循环依赖问题,任何一个bean都会放入一个ObjectFactory封装
			//也就是提前暴露,beanmap中此时还没有这个引用。
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		//省略
		// Initialize the bean instance.
		Object exposedObject = bean;
		populateBean(beanName, mbd, instanceWrapper);//依赖注入的入口,处理注入 bean内部需要注入的属性
		exposedObject = initializeBean(beanName, exposedObject, mbd);//初始化,本文不会重点介绍
		return exposedObject;
	}

bean在实例化后会放到一个ObjectFactory中,然后开始注入其他属性bean。对应本次案例,也就是上文提到的URLService已经初始化了。接下来要给它注入UrlService2了。UrlService2暂时还没有,所以首先应该实例化UrlService2。再注入UrlService2的相关属性,但是在注入UrlService2的相关属性的时候,发现需要注入UrlService。而这个UrlService 可以直接从ObjectFactory取得,所以可以破解循环依赖问题。整个循环得以破解。下面对UrlService中注入UrlService2的过程分析

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
		//省略
		if (hasInstAwareBpps || needsDepCheck) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						//主要是通过一个AutowiredAnnotationBeanPostProcessor 后置处理器 对Autowired标注的属性进行注入。当然整个方法是支持各种注入类型的,xml方式,但是这里只介绍Autowired方式。
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}
			
		}
		//省略
	}

进入Autowired后置处理器分析。

@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		
		metadata.inject(bean, beanName, pvs); //属性注入 重点
		
		return pvs;
	}
	
	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			boolean debug = logger.isDebugEnabled();
			//所有被Autowired标注的都需要依次注入
			for (InjectedElement element : elementsToIterate) {
				if (debug) {
					logger.debug("Processing injected element of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);//重点方法
			}
		}
	}
	@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
				//省略
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);//解决依赖注入重//省略
			
	}
	//省略
	if (instanceCandidate instanceof Class) {
		instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
	}
	public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
			throws BeansException {
			return beanFactory.getBean(beanName);//重新进入实例化UrlService2的过程。此过程完全类似UrlService的实例化
			所以不再赘述。直接看是怎么解决循环依赖的。
	}
	

处理UrlService2的注入项,需要注入UrlService,此时会beanMap中没有,会进入实例化UrlService的过程。但是这个过程不会执行完成。毕竟前面UrlService的实例化过程还在栈内压着呢。所以到执行doGetBean的方法时,Object sharedInstance = getSingleton(beanName);
就会将UrlService返回了。所以UrlService的第二次实例化并没有执行。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);//取到了UrlService 的封装对象
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();// 从封装对象中取得了Bean引用
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

至此UrlService2的依赖项问题解决完毕。如果UrlService2能处理完,自然UrlService也能处理完。
至此整个循环依赖的原码分析完毕。

猜你喜欢

转载自blog.csdn.net/ygy982883422/article/details/105802988