Spring的原型Bean或者Web作用域的Bean能解决循环依赖吗?

本文详细解释了Spring中如何通过@Scope注解配合ScopedProxy来处理循环依赖问题,以及4.0版本后CGLIB代理的构造函数调用变化。重点阐述了ScopedProxyFactoryBean在代理生成和依赖注入中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 这个是要分情况的,正常情况下,非单例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代理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值