欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring怎么解决循环依赖?

程序员文章站 2022-03-04 17:15:09
...

我们知道spring在创建bean的整个周期过程当中,会出现循环依赖问题 我们先拿出一个demo

我们创造出TestService和UserService之间有循环依赖

TestService:

package com.test.autowired.service;


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

import javax.annotation.PostConstruct;

@Component
public class TestService {

    //TestService 里面需要UserService 对象
	@Autowired
	UserService userService;

	public TestService() {
		System.out.println("TestService---------------无参构造器创建对象");
	}

	//bean创建完好后的回调
	@PostConstruct
	public void after(){
		System.out.println("TestService------------------bean初始化完后的回调");
	}
}

UserService:

package com.test.autowired.service;


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

import javax.annotation.PostConstruct;

@Component
public class UserService {

	//UserService 里面需要testService
	@Autowired
	TestService testService;

	public UserService() {
		System.out.println("UserService---------------无参构造器创建对象");
	}

	@PostConstruct
	public void after(){
		System.out.println("UserService------------------bean初始化完后的回调");
	}
}

上面两个类 在spring启动容器加载的时候 就会出现循环依赖问题  那么我们的spring是怎么去解决的呢?

无论是先初始化完TestService还是先初始化UserService  都需要对方的属性填充 才能完成bean的整个生命周期

下面我们来看看源码

我们直接来看finishBeanFactoryInitialization(beanFactory);这个方法才是完成bean整个初始化过程

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		//首先,初始化名字为 conversionService 的 Bean。
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal ->     getEnvironment().resolvePlaceholders(strVal));
		}
        // Initialize LoadTimeWeaverAware beans early to allow for registering their                     transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		// 没什么别的目的,因为到这一步的时候,Spring 已经开始预初始化 singleton beans 了,
		// 肯定不希望这个时候还出现 bean 定义解析、加载、注册。
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		// 开始初始化剩下的单实例bean
		beanFactory.preInstantiateSingletons();
	}
        

中间我们省略  直接看    beanFactory.preInstantiateSingletons();这个方法  我们直接进入getBean(beanName)调用的doGetBean方法

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
   final String beanName = transformedBeanName(name);
 
  Object bean;
  Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
   else {
      //prototypesCurrentlyInCreation 需要联系 getSingleton方法
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }else{
               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;
}

代码过长 我们这里只贴出部分代码 第一次我们调用 getSingleton(beanName) 来获取bean对象 spring容器刚初始化这个时候

肯定为空 所以我们就会走进第二次调用 sharedInstance = getSingleton(beanName, () -> { try {return createBean(beanName, mbd, args);}  这个是方法的重载  那么我们就进入getSingleton这个重载方法里面

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");

		//预创建bean对象
		beforeSingletonCreation(beanName);
        singletonObject = singletonFactory.getObject();
		newSingleton = true;
                

首先我们会进入beforeSingletonCreation(beanName);

if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);  }

假设我们先初始化TestSservice的bean,这个方法是将会把testService放入singletonsCurrentlyInCreation这个set里面  表示这个

beanName是将要创建的,完成beforeSingletonCreation 我们继续看    singletonObject = singletonFactory.getObject();

这里完成了一个回调  会回到我们的return createBean(beanName, mbd, args); 我们开始创建bean 我们直接进入createBean方法开面的Object beanInstance = doCreateBean(beanName, mbdToUse, args)方法

	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) {
			//开始实例化对象 而不是bean 就是new
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
        // Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", 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) {
			if (logger.isTraceEnabled()) {
				logger.trace("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);
		

		}
        
 return exposedObject;

上面也是贴出核心部分  首先我们的实例化出对象(注意对象bean是两个不同的概念)

            //开始实例化对象 而不是bean 就是new
            instanceWrapper = createBeanInstance(beanName, mbd, args); 这里通过反射实例化的是TestService对象

下面这个方法则是提供后置处理器进行处理AutowiredAnnotationBeanPostProcessor

 

    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));  这里判断是否是单列  是否允许循环依赖(默认为true) 并且是否是正在创建中              由上面的分析这个earlySingletonExposure 得到的为true  则就调用下面的

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))  将我们上面创建的对象放在二级缓存里面

下面这个方法populateBean(beanName, mbd, instanceWrapper)将是对对象进行填充 (这里就会出现自动注入 开始出现循环依赖的问题) 我们进入方法

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			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;
				}
			}
		}
}

我们省略 直接进入核心

    PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); 这里会调用AutowiredAnnotationBeanPostProcessor后置处理器的实现

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

我们会看到AutowiredAnnotationBeanPostProcessor的postProcessProperties填充属性的时候回调用metadata.inject(bean, beanName, pvs); 自动注入的方法 我们进入inject()方法  

	protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
				Assert.state(beanFactory != null, "No BeanFactory available");
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				try {
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
......
.....
...

我们可以看我们的bean工厂处理这层依赖关系  我们看value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); 点进去 我们发现我们又回到了大家数据的DefaultListableBeanFactory这个类中

@Override
	@Nullable
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
        else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

直接看最后处理方法result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);

点进去 我们找到最后的

if (instanceCandidate instanceof Class) {
                instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
            }  到此你会发现  我们又进入了beanFactory.getBean(beanName);  getBean的方法  但是这里的是获取带有注解的bean 也就是我们这里的userService 这样我们又回到原点去getSingtonObject().....等等一系列的操作

 就上面做个总结:

假如我们a注入了b   b也注入了a  那么spring容器初始化的时候 假如是先初始化A,初始化的过程中在AbstractAutowireCapableBeanFactory的doCreateBean方法中先会创建a的对象(利用反射)创建完对象后 给该对象填充属性,这时候会发现b这个对象并不存在,那么根据判断调用AutowiredAnnotationBeanPostProcessor后置处理器去处理b的bean的初始化的过程  这个时候就会来初始化b  初始化b的整个过程中 发现需要a对象  由于前面我们已经创建了a对象放在了二级缓存当中,这里b就可以直接去取出来 完成对应的初始化工作, 等b的bean初始化完成之后a陆续完成对应的初始化工作。

我们暂时对着源码分析到这里  当然这里有很多细节  需要我们对着源码断点分析