循环依赖存在一下几种情况:
- @DenpendOn 循环依赖
- 构造器参数循环依赖
- @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属性中。所以本质是不同的