spring代理循环依赖问题

1、是否属性注入都能解决循环依赖?

是的,前提是注入的不是代理对象,如果注入的是代理对象需要继续往下看。

2、产生代理就不能循环依赖?那么我们经常用到的@Transation为啥能循环依赖,也是产生代理对象的呀?

首先,不能说产生代理对象就不能循环依赖,要看代理对象是怎么产生的,毕竟spring给我们预留了三级缓存来解决代理对象带来的循环依赖。

为啥要用三级缓存来解决代理的循环依赖,这跟spring的生命周期有关,相关知识请百度,因为网上很多。

对于spring来说,有很多beanPostProcessor可以参与改变bean的生成,产生代理,也是利用beanPostProcessor,但是并不是所有的beanPostProcessor产生的bean代理都会加入三级缓存,这个是关键。加入三级缓存的代码如下:

		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方法
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}


	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
				exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
		return exposedObject;
	}

从上面代码看,加入三级缓存的前提是,产生代理的beanPostprocessor实现了SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法 。那么@Transation能支持循环依赖,是因为,这个注解产生代理对象的类是

AbstractAutoProxyCreator,这个是实现了SmartInstantiationAwareBeanPostProcessor。

3、除了看代码,怎么验证第二个问题?

首先先写两个类,A 、B 其中,A注入了b  B又注入了a,这里就满足了循环依赖,然后写两个processor,用于产生代理类,一个是普通的processor,一个是实现了SmartInstantiationAwareBeanPostProcessor产生的代理类。代码:

@Component
public class APostprocessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       // return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
        if(bean instanceof A){
        IA ia =  (IA) Proxy.newProxyInstance(A.class.getClassLoader(), new Class[]{IA.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                    return "1111";
                }
            });
            return ia;
        }
        return null;
    }
}

@Component
public class BPostprocessor implements SmartInstantiationAwareBeanPostProcessor {

    Map<String,Object> map = new HashMap<>();


    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
       // return SmartInstantiationAwareBeanPostProcessor.super.getEarlyBeanReference(bean, beanName);
        if(bean instanceof A){
            if(map.get(beanName) != null){
                return map.get(beanName);
            }
            IA ia =  (IA) Proxy.newProxyInstance(A.class.getClassLoader(), new Class[]{IA.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                    return "111111";
                }
            });
            map.put(beanName,ia);
            return ia;
        }

        return null;
    }


}

结果:当用APostprocessor产生的代理类,不能循环依赖,而用BPostprocessor 产生的代理类可以支持循环依赖

4、那为啥@Async不能支持循环依赖,而@Transactional能支持循环依赖?

当看懂了第二个问题后,这个就很好理解,因为@Async产生代理对象的类是AsyncAnnotationBeanPostProcessor,没有实现SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法,因此没有用到三级缓存,没办法解决循环依赖。而@Tranactional有实现

5、总结

普通的对象的属性注入是支持循环依赖,因为这种用到二级缓存就能解决了,而当你有代理对象产生的注入,spring支持用三级缓存来解决,但是加入到三级缓存是有条件的,就是实现SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法。因此避免循环注入报错,有以下几种解决办法:

1、不要使用代理对象注入到属性中

2、产生代理对象的地方需要实现SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference,并且把代理对象返回

3、属性注入使用@Lazy

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值