单例Bean中依赖注入Scope类型的Bean ,为什么默认会失效?

单例Bean中依赖注入Scope类型的Bean ,为什么默认会失效?

单例Bean中依赖注入Scope类型的Bean,默认会失效

我演示一下

//启动类
@ComponentScan("com.itheima.a09")
public class A09 {
    private static final Logger log = LoggerFactory.getLogger(A09.class);

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09.class);

        E bean = context.getBean(E.class);
        log.debug("{}",bean.getF1());
        log.debug("{}",bean.getF1());
        log.debug("{}",bean.getF1());
        log.debug("{}",bean.getF1());

        context.close();
    }
}

//输出结果:
com.itheima.a09.F1@3835c46
com.itheima.a09.F1@3835c46
com.itheima.a09.F1@3835c46
com.itheima.a09.F1@3835c46
发现get返回的F1都一样
@Component
public class E {

    @Autowired
    F1 f1;

    public F1 getF1(){
        return f1;
    }
}
--------
@Scope("prototype")
@Component
public class F1 {
}

虽然F1配置成了多例的Bean,但是对于E来说,因为E是单例,只会被创建一下,对应的f1,依赖注入f1的时候只会注入一次f1,所以每次返回的时候仅仅返回我们刚开始第一次依赖注入时的F1

解决方案:
@Lazy

在被注入的类的成员变量上 加一个@Lazy

ProxyMode

在被注入的目标的Bean类中 将ProxyMode设置为ScopedProxyMode.TARGET_CLASS

@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)

@Lazy,ProxyMode 这两种方式本期其实是通过代理在我们要使用被依赖注入的bean的时候每次都会给我们代理创建新的Bean,代理在获取的时候调用toString方法的时候就会创建新的被注入的多例对象

ObjectFactory
@Component
public class E {

    @Autowired
    F1 f1;

    public F1 getF1(){
        return f1;
    }

    @Autowired
    private ObjectFactory<F2> objectFactory;
    public F2 getF2(){
        return objectFactory.getObject();
    }
}

//F2还是一个多例Bean
@Scope("prototype")
@Component
public class F2 {
}
//验证
        System.out.println("--------------------------");
        log.debug("{}",bean.getF2());
        log.debug("{}",bean.getF2());
        log.debug("{}",bean.getF2());
        log.debug("{}",bean.getF2());
//此时的返回结果就都是多例Bean的结果了

这种方式是通过工厂的方式,在我们要使用被依赖注入的bean的时候工厂每次都会给我们创建新的Bean

依赖注入 Spring容器
//E中添加的代码

    @Autowired
    private AnnotationConfigApplicationContext context;
    public F3 getF3(){
        return context.getBean(F3.class);
    }

//F3
@Scope("prototype")
@Component
public class F3 {
}

//测试
        System.out.println("--------------------------");
        log.debug("{}",bean.getF3());
        log.debug("{}",bean.getF3());
        log.debug("{}",bean.getF3());
        log.debug("{}",bean.getF3());
/*
com.itheima.a09.F3@6dc17b83
com.itheima.a09.F3@5e0826e7
com.itheima.a09.F3@32eff876
com.itheima.a09.F3@8dbdac1 
*/

通过注入容器的方式每次当我们使用F3的时候,直接通过容器.getBean的方式就一定会得到F3

Scope所定义的类型

总结

单例中注入其它类型的Scope解决方案:

  • @Lazy

  • ProxyMode设置为ScopedProxyMode.TARGET_CLASS

  • 依赖注入 objectFactory<>

  • 依赖注入 AP容器

前两种实质都是通过代理的方式来实现创建的

不推荐使用代理的方式,原因;

  • 一方面有一定的性能损耗
  • 用容器或工厂去拿显得更为简洁

此处我演示的是 单例中注入多例的解决方案,但是对其它的三种Scope类型同样试用


以上四种解决方案有一个共同点:推迟其它ScopeBean的获取

在单例bean创建的时候并没有也创建被注入的依赖bean,而是通过中间间接创建并加入所依赖的bean对象,再到运行时获取这个多例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C_x_330

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值