spring DenpendOn循环依赖判断原理

循环依赖存在一下几种情况:

  1. ​ @DenpendOn 循环依赖
  2. ​ 构造器参数循环依赖
  3. ​ @Autowire这样的属性依赖

今天主要说说@DenpendOn循环依赖的判断,spring首先解析出@DependOn所提供的直接依赖,然后通过嵌套查询的方式判断是否存在依赖循环,下边我们通过问答的方式来分析判断原理

问题:spring在什么时候解析@DependOn,存储这些直接依赖的

需要解析注解,读过源码的朋友都知道,这一步应该是在将class转换为BeanDefinition的时候,下边是解析源码,查找这个代码非常深入,最终我们在doScan()包扫描类中找到了AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);这个方法调用,@DependOn也是在这里解析的,

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();

		for (String basePackage : basePackages) {
			//扫描指定包下的类,这这些符合条件的类转换为BeanDefinition
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				//针对不同的BeanDefinition做不同的后置处理, 这里处理AbstractBeanDefinition
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				//处理AnnotatedBeanDefinition的后置处理
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}

				//检查当前BeanDefinition是否依据存在
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}



//处理通用BeanDefinition注解
	//设置LAZY, Primary, DependsOn, Role, Description
	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
		//获取类上的@LAZY注解属性
		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);

		//lazy元数据属性的判断处理,需要在研究一下
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		} else if (abd.getMetadata() != metadata) {
			lazy = attributesFor(abd.getMetadata(), Lazy.class);
			if (lazy != null) {
				abd.setLazyInit(lazy.getBoolean("value"));
			}
		}

		//设置Primary
		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}

		//设置DependsOn
		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
		if (dependsOn != null) {
			abd.setDependsOn(dependsOn.getStringArray("value"));
		}

		//设置Role
		AnnotationAttributes role = attributesFor(metadata, Role.class);
		if (role != null) {
			abd.setRole(role.getNumber("value").intValue());
		}
		//设置描述
		AnnotationAttributes description = attributesFor(metadata, Description.class);
		if (description != null) {
			abd.setDescription(description.getString("value"));
		}
	}

问题:找到直接依赖,那么是如果判断是否循环依赖的

判断DependOn循环依赖,spring在bean实例化之前完成,查看源码,我们能看到在spring doGetBean()方法中有如下一段代码,这段代码中有一个循环直接依赖调用isDependent(beanName, dep)方法,beanName是当前bean名称,dep是直接DependOn依赖,那么isDependent()方法是如何判断的,接着看源码,通过代码我们知道,通过递归的方式判断是否存在依赖,但是我们看到在该方法中有用到一个Map,这个map存储了bean的依赖,那么这个数据在什么时候存储进去的呢,其实在isDependent()方法后就有registerDependentBean(dep, beanName);这样一个方法调用,就是在这个时候将依赖添加到了map集合中的

/**
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * 真正获取Bean实例的方法
	 *
	 * @param name the name of the bean to retrieve
	 * @param requiredType the required type of the bean to retrieve
	 * @param args arguments to use when creating a bean instance using explicit arguments
	 * (only applied when creating a new instance as opposed to retrieving an existing one)
	 * @param typeCheckOnly whether the instance is obtained for a type check,
	 * not for actual use
	 * @return an instance of the bean
	 * @throws BeansException if the bean could not be created
	 */
	@SuppressWarnings("unchecked")
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		//获取实际的beanName,也就是FactoryBean自己的,&beanName, beanName为调用getObject()返回bean的名称
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		//获取单例对象
		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 + "'");
				}
			}
			//首先判断是不是FactoryBean, 如果是FactoryBean, 这获取getObject()对象
			//但是首先还是要从单例池中查找,然后从缓存中查找,最后才是实际调用getObject()方法
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			//获取父beanDefinition,这里会嵌套查找
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				} else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				} else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				} else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			//如果并非只是类型检查
			if (!typeCheckOnly) {
				//标记bean已经被创建
				//向alreadyCreated中添加beanName,如果alreadyCreated中不存在
				//移除mergedBeanDefinitions中beanName
				markBeanAsCreated(beanName);
			}

			try {
				//执行合并
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				//判断合并后的beanDefinition是不是抽象类, 如果时抽象类,将抛出异常
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				//获取依赖bean,如果存在@DependsOn注解,那么这项依赖bean将会被先实例化
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						//判断循环依赖,如果A DependOn B, 同时B DependOn A, 则出现循环依赖
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//设置依赖,这样可以保证在bean销毁前先销毁依赖bean
						//会将dependOn设置到dependentBeanMap
						registerDependentBean(dep, beanName);
						try {
							//首先实例化依赖bean实例化对象/又是以嵌套获取Bean实例
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				//创建单例实例
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							//调用创建Bean实例方法
							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;
						}
					});
					//判断当前是否不是FactoryBean,如果是FactoryBean,这需要调用getObject()获取真正的bean
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				//创建原型实例
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				//其他类型实例
				else {
					//获取ScopeName
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						//需要注意的是,这里是通过scope调用的bean创建
						//这种创建方法与单例模式创建有几分相似
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// Check if required type matches the type of the actual bean instance.
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				//类型转换
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}
	
	
	/**
	 * Determine whether the specified dependent bean has been registered as
	 * dependent on the given bean or on any of its transitive dependencies.
	 * @param beanName the name of the bean to check
	 * @param dependentBeanName the name of the dependent bean
	 * @since 4.0
	 */
	protected boolean isDependent(String beanName, String dependentBeanName) {
		//互斥
		synchronized (this.dependentBeanMap) {
			return isDependent(beanName, dependentBeanName, null);
		}
	}

	//判断循环依赖
	private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
		//防止递归死循环
		if (alreadySeen != null && alreadySeen.contains(beanName)) {
			return false;
		}
		//拿到当前bean名称,这里不是别名,真正的bean名称
		String canonicalName = canonicalName(beanName);
		//获取依赖bean名称,在dependentBeanMap中存储这当前存在依赖关系的bean名称
		Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
		if (dependentBeans == null) {
			return false;
		}
		if (dependentBeans.contains(dependentBeanName)) {
			return true;
		}
		for (String transitiveDependency : dependentBeans) {
			if (alreadySeen == null) {
				alreadySeen = new HashSet<>();
			}
			alreadySeen.add(beanName);
			//递归判断
			if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
				return true;
			}
		}
		return false;
	}

查看更多源码我们知道,dependentBeanMap的添加地方放并非此一处,在Inject()方法还有,而 在这个地方添加进去还有@Autowire这样的属性依赖。

我们知道Dependon这样的循环依赖是没有办法解决的,一旦代码写定,那么依赖关系就确定,只能通过改写代码打断这样的依赖,否则只会抛出异常,因为这些依赖判断是在实例创建以前判断,不同意@Autowire这样的属性依赖,这样的依赖是在当前bean依旧实例化,自己可以作为属性注入到其他bean属性中。所以本质是不同的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值