- 这个是要分情况的,正常情况下,非单例Bean是无法解决循环依赖的,但是有特殊情况
- 但是当Bean标注了@Scope,并且设置了该Bean需要使用作用域代理的时候,可以处理循环依赖
-
案例
-
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) public class SpringBootDemo { public static void main(String[] args) { SpringApplication.run(SpringBootDemo.class); } @RestController static class Controller { @PostConstruct public void init(){ ScopeD scopeD = SpringUtil.getBean(ScopeD.class); ScopeE scopeE = SpringUtil.getBean(ScopeE.class); System.out.println(scopeD.getClass().getName()); System.out.println(scopeE.getClass().getName()); } } @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) @Component static class ScopeD { public ScopeD(ScopeE scopeE) { System.out.println("scopeD构造方法" + scopeE.getClass().getName()); } } @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) @Component static class ScopeE { public ScopeE(ScopeD scopeD) { System.out.println("scopeE构造方法" + scopeD.getClass().getName()); } } }
运行结果
- 详细的可以看文章Spring中@Scope注解的处理原理
-
原因
- 当需要标注了@Scope类需要生成代理的时候,此时会给这个类生成一个代理类的BeanDefinition,而这个BeanDefinition设置生成的Bean的类为ScopedProxyFactoryBean,从ScopedProxyFactoryBean中生成代理对象,在ScopedProxyFactoryBean中,在setBeanFactory方法中,就已经将代理对象生成了,就等着使用getObject去获取
- 附上官网的话,从 Spring 4.0 开始,代理对象的构造函数不再被调用两次,因为 CGLIB 代理实例是通过 Objenesis 创建的。仅当您的 JVM 不允许绕过构造函数时,您才可能会看到来自 Spring 的 AOP 支持的双重调用和相应的调试日志,说白了,就是4.0开始,CGLIB生成的代理对象你写构造方法查看构造方法是否执行是无法看到了,只是在JVM内部执行
- 为什么能解决循环依赖呢? 因为要注入的对象是从ScopedProxyFactoryBean中获取已经生成好的代理对象,要注入对象的时候,直接从ScopedProxyFactoryBean获取就好了
- 提示: 真实Bean的beanName为scopeTarget.beanName,ScopedProxyFactoryBean的beanName则是真实Bean的原始beanName,例如 A类,beanName为scopeTarget.a,而ScopedProxyFactoryBean的beanName为a,这个与普通的FactoryBean不一样,普通的BeanName为&beanName,所以,当根据原始beanName(a)去获取的时候,获取的是ScopedProxyFactoryBean这个bean,然后通过这个bean去getobject对象,这个时候之前,代理对象已经生成了,所以直接获取到
- 总之一句话,绕过了原始对象的,利用特殊的ScopedProxyFactoryBean来解决@Scope代理
Spring的原型Bean或者Web作用域的Bean能解决循环依赖吗?
于 2024-03-14 14:54:14 首次发布