@Async注解导致的启动异常

142 阅读3分钟

背景

项目启动时异常了,出现了BeanCurrentlyInCreationException异常

demo1.png

异常抛出地方的代码

    // AbstractAutowireCapableBeanFactory.doCreateBean 
    if (earlySingletonExposure) { 
       // 从缓存中获取,注意这里第二个参数是false,也就是说只能从一级缓存、二级缓存中获取 
       // 因为此时还未放入一级缓存,所以肯定是没有的,只能从二级缓存中获取 
       Object earlySingletonReference = getSingleton(beanName, false); 
       if (earlySingletonReference != null) { 
          // 比较二级缓存中的bean实例是否与初始化后的bean实例相等,此时发现并不相等 
          if (exposedObject == bean) { 
             exposedObject = earlySingletonReference; 
          } 
          // 接下来就会判断这个bean是否有其他bean进行依赖,如果有则说明注入到其他bean的依赖不是最终包装过后的bean 
          else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { 
             String[] dependentBeans = getDependentBeans(beanName); 
             Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); 
             for (String dependentBean : dependentBeans) { 
                if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { 
                   actualDependentBeans.add(dependentBean); 
                } 
             } 
             // 所以这里就会抛异常(开头我们看见的异常信息) 
             if (!actualDependentBeans.isEmpty()) { 
                throw new BeanCurrentlyInCreationException(beanName, 
                      "Bean with name '" + beanName + "' has been injected into other beans [" + 
                      StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + 
                      "] in its raw version as part of a circular reference, but has eventually been " + 
                      "wrapped. This means that said other beans do not use the final version of the " + 
                      "bean. This is often the result of over-eager type matching - consider using " + 
                      "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); 
             } 
          } 
       } 
    }

demo2.png

出现的原因

bean的创建过程

  1. 在创建对象A的时候,填充属性之前会提前暴露对象A在三级缓存中
    // 三级缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    // 在bean在实例化时,提前将还未完全实例化好的早期bean通过缓存向外界暴露
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  1. 在填充对象A属性时发现依赖了对象B,会尝试从缓存中获取对象B
  2. 在创建对象B后,填充属性时发现依赖了对象A,会尝试从缓存中获取对象A

    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);

    public Object getSingleton(String beanName) {
    	// allowEarlyReference 为true
    	return getSingleton(beanName, true);
    }

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
      // 从一级缓存中获取
    	Object singletonObject = this.singletonObjects.get(beanName);
      // bean 未实例化,并且正在创建
    	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    		synchronized (this.singletonObjects) {
    			// 从二级缓存中获取
    			singletonObject = this.earlySingletonObjects.get(beanName);
    			// 早期缓存对象为空并且 allowEarlyReference 为 true
    			if (singletonObject == null && allowEarlyReference) {
    				// 从三级缓存获取早期单例的工厂对象
    				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    				if (singletonFactory != null) {
    					// 执行getObject
    					singletonObject = singletonFactory.getObject();
    					// 放入早期
    					this.earlySingletonObjects.put(beanName, singletonObject);
    					this.singletonFactories.remove(beanName);
    				}
    			}
    		}
    	}
    	return singletonObject;
    }

1.  然后将A注入到对象B中
2.  对象B完成创建、初始化后,继续A的流程,将对象B注入到对象A属性中。
3.  对象A进行初始化

那么加@Async注解之后,为什么会异常


    // 从三级缓存获取factoryBean 之后执行getObject
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    	Object exposedObject = bean;
    	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    		for (BeanPostProcessor bp : getBeanPostProcessors()) {
    			// 实现了 SmartInstantiationAwareBeanPostProcessor
    			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
    				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
    				exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
    			}
    		}
    	}
    	return exposedObject;
    }

demo3.png AsyncAnnotationBeanPostProcessor并没有实现SmartInstantiationAwareBeanPostProcessor所以getEarlyBeanReference并不会处理

AsyncAnnotationBeanPostProcessor是在bean实例化之后处理生成代理类

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
    	、、、省略、、、
    	}
    	// 判断一下bean是否能匹配到对应类型的advisor
    	if (isEligible(bean, beanName)) {
    		ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
    		if (!proxyFactory.isProxyTargetClass()) {
    			evaluateProxyInterfaces(bean.getClass(), proxyFactory);
    		}
    		proxyFactory.addAdvisor(this.advisor);
    		customizeProxyFactory(proxyFactory);
    		// 创建代理对象
    		return proxyFactory.getProxy(getProxyClassLoader());
    	}

    	// No proxy needed.
    	return bean;
    }

demo4.png

**@Transactional循环依赖时为什么不会启动异常**

demo5.png

    // 代理对象的早期引用
    private final Set<Object> earlyProxyReferences = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
    	Object cacheKey = getCacheKey(bean.getClass(), beanName);
    	if (!this.earlyProxyReferences.contains(cacheKey)) {
    		// 加入集合
    		this.earlyProxyReferences.add(cacheKey);
    	}
    	return wrapIfNecessary(bean, beanName, cacheKey);
    }

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    	、、、省略、、、
    	// 获取匹配的 advice.
    	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    	if (specificInterceptors != DO_NOT_PROXY) {
    		this.advisedBeans.put(cacheKey, Boolean.TRUE);
    		// 创建代理对象
    		Object proxy = createProxy(
    				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    		this.proxyTypes.put(cacheKey, proxy.getClass());
    		return proxy;
    	}

    	this.advisedBeans.put(cacheKey, Boolean.FALSE);
    	return bean;
    }

    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    	if (bean != null) {
    		Object cacheKey = getCacheKey(bean.getClass(), beanName);
    		// 集合中没有才会进行包装
    		if (!this.earlyProxyReferences.contains(cacheKey)) {
    			return wrapIfNecessary(bean, beanName, cacheKey);
    		}
    	}
    	return bean;
    }

demo6.png

解决

  1. 避免循环依赖,把@Async的方法单独处理

  2. @Lazy注解

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

        	if(){
        		、、、省略、、、
        	}
        	else {
        		// @Lazy标识的属性,生成懒加载的代理对象
        		Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
        		// 没有@Lazy标识,getBean
        		if (result == null) {
        			result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        		}
        		return result;
        	}
        }

        public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
        	// @Lazy标识的属性,生成代理类返回
        	return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
        }