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