在我们同时使用 @Transaction与@Async 一不小心就会触发 BeanCurrentlyInCreationException(多版本循环依赖的错误) ,
也就是说spring缓存中单例对象有多个版本,这违反了,单例原则
先开一下对象的在spring中的内存图
例如下面这个代码:
@Component
public class AsynService {
@Autowired
private AsynService asynService;
@Transactional
@Async
public void a(){
}
}
我们先看一看这个错误是怎么被触发的
第一次 getBean() 一步一步的跟 会进入到这个方法
AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
删除部分无法代码
....
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//设置三级缓存
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 依赖注入
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//这里会进行AOP
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
在 populateBean() 中会进行依赖注入,注入属性 asynService 会第二次getBean(),第二次会尝试从缓存中拿。
下面是从缓存拿取的代码
DefaultSingletonBeanRegistry#getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从一级缓存中获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//从三级缓存中获取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
最后会从三级缓存中拿,三级缓存获取时会进入下面的方法
AbstractAutowireCapableBeanFactory#getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//BeanPostProcessor 埋点,这个地方可能会产生代理对象
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
//只有AOP切面,就会产生代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return null;
}
}
}
}
return exposedObject;
}
这个方法我们本次只需要关注 AbstractAutoProxyCreator.class,下面是代码
AbstractAutoProxyCreator.getEarlyBeanReference
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
//这里 可以理解为 cacheKey 就是 beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
//缓存提前暴露的 对象Key,记住这里后面会使用到
this.earlyProxyReferences.add(cacheKey);
}
//代理的创建
return wrapIfNecessary(bean, beanName, cacheKey);
}
下面我们看看 wrapIfNecessary() 干了些什么
AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//删除了部分无关的代码
...
// Create proxy if we have advice.
//获取这个当前类(AsynService)是否有切面,这里会找到一个@Transaction 相关的切面
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;
}
wrapIfNecessary 会生成代理 我们就把它叫做 aopPoxy ,接着会把代理对象(aopPoxy )放入到二级缓存,并删除三级缓存,到此第二次getBean()就完成了,同时第一次getBean() 执行 populateBean()也就(本次关心的流程)完成了,现在进入了initializeBean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
//删除部分无关代码
...
if (mbd == null || !mbd.isSynthetic()) {
//BeanPostProcess 的 postProcessAfterInitialization() 方法埋点
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
我在本次只需要关注两 BeanPostProcess
1.AbstractAutoProxyCreator#postProcessAfterInitialization
因为第二次创建时 向earlyProxyReferences 设置了key,因此,这个方法返回的是bean本身
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
2.AsyncAnnotationBeanPostProcessor#postProcessAfterInitialization
Async 的入口类 ,这个返回的是代理 ,我们就把它叫做 asyncPoxy
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
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 async proxy needed.
return bean;
}
到此我们就获取到了两个代理:
1.第二getBean() 二级缓存中的 aopPoxy,
2.第一次getBean() 时initializeBean()f方法返回的 asyncPoxy
下面是触发逻辑代码
if (earlySingletonExposure) {
//从缓存中获取,此时可以获取到二级缓存中的aopPoxy
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//这里的 exposedObject = asyncPoxy ,bean = bean
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
//最后会进入这里,然后就会抛出异常
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
我们现在了解了导致 BeanCurrentlyInCreationException 的原因,最后总结一下:
1.依赖注入导致 二级缓存中有 aopPoxy
2. 埋点 postProcessAfterInitialization 会 产生 exposedObject = asyncPoxy
3. 最后判断 发现 缓存中有 aopPoxy,并且 exposedObject != bean 异常就触发了
要解决不触发异常,我们就有只有让判断不成立就行了,因此 要么让 @Async 使用 aop 的入口类,
要么让缓存中没有值,入口了是Async 模块定义好的,我们不好处理,最简单的办法就是让缓存中没有数据
刚好@Lazy就能实现,让缓存中没有数据
接下来我们看看@Lazy 是怎实现的
populateBean() 方法中如果注入点被@Lazy 修饰就不会触发getBean(),而是生成一个代理对象直接赋值给注入的对象,不getBean() 就三级缓存就不会有数据,异常判断就不成立了
下面是@Lazy 的核心代码
ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final String beanName) {
Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
"BeanFactory needs to be a DefaultListableBeanFactory");
final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
//删除部分代码
....
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
Class<?> dependencyType = descriptor.getDependencyType();
if (dependencyType.isInterface()) {
pf.addInterface(dependencyType);
}
//生成代理
return pf.getProxy(beanFactory.getBeanClassLoader());
}
最后我想说:@Async 与其他产生代理的注解最好不要写在一个类中,如果写在一起最后类中的注入点 都加上@Lazy