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
本文深入探讨了Spring框架中如何处理循环依赖,特别是涉及代理对象的情况。文章指出,普通的属性注入可以解决循环依赖,但当涉及到代理对象时,Spring使用三级缓存策略。@Transactional注解能够支持循环依赖,因为它所对应的AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor,而@Async不支持是因为其使用的AsyncAnnotationBeanPostProcessor未实现相应接口。通过实例代码,作者展示了如何验证这一结论,并总结了解决循环依赖的几种方法,包括避免代理注入、实现特定接口以及使用@Lazy注解。

369

被折叠的 条评论
为什么被折叠?



