zoukankan      html  css  js  c++  java
  • springboot bean的循环依赖实现 源码分析

    springboot bean的循环依赖实现 源码分析

    本文基于springboot版本2.5.1

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.1</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    

    本文主要聚焦在循环依赖部分,主要用单例bean来进行讲解,其他bean实现的流程不会过多涉及。

    1、什么叫循环依赖呢

    简单来说就是springboot容器中的多个bean,如A、B两个bean,A有属性B需要注入,B有属性A需要注入,形成相互依赖的情况。

    看下代码,就是类似下面这种情况

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ServiceA {
        @Autowired
        private ServiceB serviceB;
    }
    
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ServiceB {
        @Autowired
        private ServiceA serviceA;
    }
    
    

    上面有两个bean,分别是ServiceA,ServiceB。ServiceA中需要注入ServiceB的实例,ServiceB中需要注入ServiceA的实例,这就是一种典型的循环依赖,其他还有方法参数循环依赖的场景等等,但是它们的内部实现基本是一样的。

    2、具体出现循环依赖的代码逻辑

    1. 获取bean的方法

      在springboot中默认的beanFactory是DefaultListableBeanFactory,在我们获取bean对象的时候,如果bean对象存在就直接返回,如果不存在,就先创建bean对象再返回。

      我们先看下我们获取bean的常用方法都有哪些

      public <T> T getBean(Class<T> requiredType) throws BeansException
      public Object getBean(String name) throws BeansException
      public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException
      public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
      public void preInstantiateSingletons() throws BeansException 
      

      常用的获取bean的方法主要有上面几个和它们的重载版本,对于第3行、第4行、第5行最终都会调用到第2行的方法来获取bean。而它也会通过调用doGetBean(在AbstractBeanFactory这个类中)来获取bean

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

      第1行的方法也会调用doGetBean来获取bean

      	public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
      			throws BeansException {
      
      		return doGetBean(name, requiredType, args, false);
      	}
      

      所有最终获取bean的方法都是

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

      这个方法,这个方法是protected的,是不对外提供的。所以我们不能直接调用它,只能通过上面提供的5个方法来获取bean对象。

    2. 下面我们从doGetBean这里来看下serviceA创建的过程

      	protected <T> T doGetBean(
      			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      			throws BeansException {
      			//如果bean之前存在,这里返回的shareInstance就是非空,就会从后面的if分支中返回,如果bean之前不存在,就会执行后面的bean创建及注入属性的过程
      			Object sharedInstance = getSingleton(beanName);
      			if (sharedInstance != null && args == null) {
      			......
      			//如果当前不只是检查,而且是创建bean,这个参数就是false,在这里就会做个bean创建的标记,把beanName 加到alreadyCreated里面去
      			if (!typeCheckOnly) {
      				markBeanAsCreated(beanName);
      			}
      				//我们当前要创建的bean是单例的,就会走到这里去,下面我们走到里面的调用去看看
      				// Create bean instance.
      				if (mbd.isSingleton()) {
      					sharedInstance = getSingleton(beanName, () -> {
      						try {
      							return createBean(beanName, mbd, args);
      						}
      						catch (BeansException ex) {
      							// Explicitly remove instance from singleton cache: It might have been put there
      							// eagerly by the creation process, to allow for circular reference resolution.
      							// Also remove any beans that received a temporary reference to the bean.
      							destroySingleton(beanName);
      							throw ex;
      						}
      					});
      					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
      				}
      
      		}
      
      	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
      		Assert.notNull(beanName, "Bean name must not be null");
      		synchronized (this.singletonObjects) {
                      ......
                      //这里会把当前bean的名字加入到当前正在创建的单例对象集合singletonsCurrentlyInCreation中
      				beforeSingletonCreation(beanName);
      				......
      				try {
                          //这里就是调用上面的return createBean(beanName, mbd, args);这个方法,我们进这里面去看看
      					singletonObject = singletonFactory.getObject();
      					newSingleton = true;
      				}
      				......
      			}
      			return singletonObject;
      		}
      	}
      
      
      	@Override
      	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      			throws BeanCreationException {
      		......
      		// Make sure bean class is actually resolved at this point, and
      		// clone the bean definition in case of a dynamically resolved Class
      		// which cannot be stored in the shared merged bean definition.
              //在这里获取要创建的bean的class对象
      		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
      		......
      		try {
                  //调用这里来创建,我们再走到这里面去看看
                  //3个参数分别为
                  //1、beanName  bean对象的名字
                  //2、mbdToUseRootBeanDefinition对象,可以认为就是bean的元数据信息,包含bean的类对象,bean的类上注解,bean实际位置路径等等
                  //3、args  bean对象的构造方法的实参,这里一般是空的
      			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      			if (logger.isTraceEnabled()) {
      				logger.trace("Finished creating instance of bean '" + beanName + "'");
      			}
      			return beanInstance;
      		}
      		......
      	}
      
      
      protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
      
         ......
         //真正创建bean对象是在这里,这里返回的instanceWrapper是bean对象的类实例的包装对象BeanWrapper
         if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
         }
         //这里的bean就是实际创建的bean对象的类实例
         Object bean = instanceWrapper.getWrappedInstance();
         Class<?> beanType = instanceWrapper.getWrappedClass();
         if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
         }
      	......
         // Eagerly cache singletons to be able to resolve circular references
         // even when triggered by lifecycle interfaces like BeanFactoryAware.
         //看上面的注释大概也能明白, 大概意思就是早期的单例缓存,为了解决由 BeanFactoryAware等等触发的循环依赖
         //mbd.isSingleton()  表示bean是单例的(这个是bean对应的类上的,默认就是单例),
         //this.allowCircularReferences 允许循环引用,这个是beanFactory的成员属性,默认也是true
         //isSingletonCurrentlyInCreation(beanName) 表示是否在当前正在创建的bean集合中。beforeSingletonCreation(beanName);我们在前面执行过这句就加到正在创建的bean集合中了
         //这里earlySingletonExposure 就是true了,会进到if分支中
         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");
            }
            //这句主要是将将() -> getEarlyBeanReference(beanName, mbd, bean) 这个lambda表达式存储到this.singletonFactories集合中
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
         }
      
         // Initialize the bean instance.
         Object exposedObject = bean;
         try {
            //在这里就会进行属性填充,完成成员注入等等,也就是在这里serviceA这个bean会注入serviceB这个成员属性,我们走进这个方法去看看
            populateBean(beanName, mbd, instanceWrapper);
            ......
         }
       	......
      
         return exposedObject;
      }
      
      	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
      		......
      		if (hasInstAwareBpps) {
      			if (pvs == null) {
      				pvs = mbd.getPropertyValues();
      			}
      			//真正的属性注入是在这里完成的,aop也是在这里来完成的。这里是获取beanFactory中的InstantiationAwareBeanPostProcessor对bean对象进行增强
      			//如果属性注入用的是@Resource,就会用CommonAnnotationBeanPostProcessor来完成
      			//如果属性注入用的是@Autowired,就会用AutowiredAnnotationBeanPostProcessor来完成
      			//如果是AOP 就会使用InfrastructureAdvisorAutoProxyCreator来生成对应的代理对象
      			//我们这里使用的是@Autowired,所以会用AutowiredAnnotationBeanPostProcessor来完成注入。我们走到它的postProcessProperties的去看看
      			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
      				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
      				......
      	}
      
      	@Override
      	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
              //这里主要是获取bean的类属性和方法上的org.springframework.beans.factory.annotation.Autowired,org.springframework.beans.factory.annotation.Value注解来进行注入
      		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
      		try {
                  //继续进去看看
      			metadata.inject(bean, beanName, pvs);
      		}
      		......
      	}
      
      public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      		 ......
      		 //对每一个属性分别进行注入,继续进去
               element.inject(target, beanName, pvs);
            }
         }
      }
      
      
        		@Override
        		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        			Field field = (Field) this.member;
        			Object value;
        			//如果之前缓存过就从缓存取,我们是第一次注入,所以之前没有缓存,不会走这个分支
        			if (this.cached) {
        				try {
        					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
        				}
        				catch (NoSuchBeanDefinitionException ex) {
        					// Unexpected removal of target bean for cached argument -> re-resolve
        					value = resolveFieldValue(field, bean, beanName);
        				}
        			}
        			else {
        				//会走这里来解析字段的值,再进去
        				value = resolveFieldValue(field, bean, beanName);
        			}
        			if (value != null) {
        				ReflectionUtils.makeAccessible(field);
        				field.set(bean, value);
        			}
        		}
      
      
      
      		@Nullable
      		private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
      			//创建字段的包装类DependencyDescriptor
      			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
      
      			try {
      				//调用这里完成对应字段值的查找,再进去
      				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
      			}
      			catch (BeansException ex) {
      				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
      			}
      			synchronized (this) {
      				//获取到值之后,进行缓存
      				if (!this.cached) {
      						......
      					}
      					this.cachedFieldValue = cachedFieldValue;
      					this.cached = true;
      				}
      			}
      			return value;
      		}
      	}
      
      	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 {
      			//当前的类是一个普通的class,会走到这里面,由于我们的bean没有Lazy注解,所以这里返回时null,走到下面的if分支
      			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
      					descriptor, requestingBeanName);
      			if (result == null) {
      				//在这里我们看下这里的入参。
      				//descriptor是包含了需要注入的字段的信息。
      				//requestingBeanName是当前正在创建的bean的名字serviceA,
      				//autowiredBeanNames是当前需要注入的字段的对应的bean的名字的集合,这里只有serviceB
      				//typeConverter这个是进行注入时做类型转换的,这里我们可以不用关注这个
      				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
      			}
      			return result;
      		}
      	}
      
      	@Nullable
      	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
      			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
      			......
      			if (instanceCandidate instanceof Class) {
      				//又会调用到这里,我们再进入到DependencyDescriptor的resolveCandidate去看看
                      //注意:这里的autowiredBeanName是我们需要注入的属性名这里是serviceB
      				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
      			}
      			......
      	}
      
      
      	public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
      			throws BeansException {
      		//看到没,到这里就出现循环调用了,到这里又会重新调用beanFactory.getBean("serviceB")去创建serviceB的bean对象,完成后注入到serivceA对应的Bean上的属性上来,这时代码又会从本节开头的位置开始执行,先创建serviceB对象实例,再去注入serviceB对象的serviceA属性。
              //最终会执行到beanFactory.getBean("serviceA")这里
      		return beanFactory.getBean(beanName);
      	}
      

      就是下面图的样子

    3、解决循环依赖的代码实现

    接着上面的beanFactory.getBean("serviceA")这行代码我们继续往下看

    这次又会走到这里

    	protected <T> T doGetBean(
    			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    			throws BeansException {
    		//我们第二部分就是从这里开始的,又走回来了,但这次又会有所不同
    		String beanName = transformedBeanName(name);
    		Object beanInstance;
    
    		// Eagerly check singleton cache for manually registered singletons.
    		//这次我们这里返回的就不是空了,sharedInstance对象的值就是对应serviceA的bean对象了,这次就会从if分支中返回,而之前我们不会进这里的if分支而是进入else分支导致后面出现了循环依赖的问题,这次我们进到这个方法看看
    		Object sharedInstance = getSingleton(beanName);
    		if (sharedInstance != null && args == null) {
    			if (logger.isTraceEnabled()) {
    				if (isSingletonCurrentlyInCreation(beanName)) {
    					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
    							"' that is not fully initialized yet - a consequence of a circular reference");
    				}
    				else {
    					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
    				}
    			}
    			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    		}
    
    	@Nullable
    	public Object getSingleton(String beanName) {
    		//再点进去
    		return getSingleton(beanName, true);
    	}
    
    	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    		// Quick check for existing instance without full singleton lock
    		Object singletonObject = this.singletonObjects.get(beanName);
             //这里由于当前的serviceA bean还没完成创建,所以这里singletonObject返回的是空,
            //再看看 isSingletonCurrentlyInCreation(beanName)这里,由于我们在创建serviceA过程中有这么一句beforeSingletonCreation(beanName)(不清楚这句的搜索下本文,上面就有讲到),所有这个条件是true。这时我们就会进入if分支中
    		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    			singletonObject = this.earlySingletonObjects.get(beanName);
               //由于我们是第一次进入这里,所以this.earlySingletonObjects.get(beanName)返回的也是null
               //我们的入参 allowEarlyReference是true,会继续进到这个if分支中
    			if (singletonObject == null && allowEarlyReference) {
    				synchronized (this.singletonObjects) {
    					// Consistent creation of early reference within full singleton lock
    					singletonObject = this.singletonObjects.get(beanName);
                        //这里的singletonObject还是null,继续进到if分支
    					if (singletonObject == null) {
    						singletonObject = this.earlySingletonObjects.get(beanName);
    						if (singletonObject == null) {
                                //最终会走到这里,在创建serviceA对象之后,属性注入之前,执行了这句 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))(不清楚的搜索下本文,上面有说到),所以这里返回的singletonFactory是个lamdba表达式,getEarlyBeanReference(beanName, mbd, bean))附带了3个参数,第一个beanName是serivceA,mdb是对应serviceA的附带serviceA元数据信息的RootBeanDefinition对象,bean就是创建出来的serviceA对象
    							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    							if (singletonFactory != null) {
                                    //这里就会调用getEarlyBeanReference(beanName, mbd, bean)对serviceA对象进行一个getEarlyBeanReference增强后返回,返回后放置到earlySingletonObjects中,并从singletonFactories中删除
    								singletonObject = singletonFactory.getObject();
    								this.earlySingletonObjects中,并从.put(beanName, singletonObject);
    								this.singletonFactories.remove(beanName);
    							}
    						}
    					}
    				}
    			}
    		}
    		return singletonObject;
    	}
    

    最终在serviceA 这个bean创建完成后,就会从singletonsCurrentlyInCreation移除掉

    	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    				......
    				finally {
    					//在这里从singletonsCurrentlyInCreation中移除掉
    					afterSingletonCreation(beanName);
    				}
    				if (newSingleton) {
    					//将serviceA bean对象添加到singletonObjects,registeredSingletons中
    					//从singletonFactories,earlySingletonObjects中移除掉
    					addSingleton(beanName, singletonObject);
    				}
    			}
    			return singletonObject;
    		}
    	}
    

    所以整个获取serviceA的流程就是这样了,

    1、首先去创建serviceA这个bean,

    • 由于它有个属性serviceB,在创建完serviceA对象后,就会去进行serviceB的属性注入,

    • 这时由于serviceB之前没有生成,这时又会去创建serviceB这个bean,

    • 先创建serviceB对象,然后再进行serviceA这个属性的注入,

    • 继续去获取serviceA这个bean,第二次进入获取serviceA的流程,这时从之前缓存的lambda表达式中获取到之前创建的serviceA的引用返回。

    2、总结下关键的代码点

    • 创建bean对象之前调用beforeSingletonCreation(beanName)将bean对象名字添加到singletonsCurrentlyInCreation集合中
    • 创建bean对象对应的类实例后调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));添加到singletonFactories中
    • 在循环依赖中第二次调用到创建bean对象时,调用getSingleton(beanName, true)时,从singletonFactories中返回对应的早期bean对象的引用,并添加到earlySingletonObjects中
  • 相关阅读:
    with ,Row_Number,DateDiff,DateAdd用法学习
    jmeter 读取mysql数据库
    fidder 自动保存请求内容
    redis 常用方法整理
    解决:EXCEL复制粘贴,精度丢失
    MYSQL 创建常见问题
    MYSQL 存储过程、函数、临时表、游标
    MYSQL 测试常用语句使用技巧
    3-6
    selenium3 下载、配置
  • 原文地址:https://www.cnblogs.com/wbo112/p/14938678.html
Copyright © 2011-2022 走看看