spring中singleton依赖prototype问题整理

最近在项目开发过程中碰到了singleton bean中依赖prototype bean的问题,在官网和社区学习了一下,发现有一些使用方法是错误的,在这里自己测试了几个正确的使用方式,在这里供大家交流。
首先是示例代码,这是省略版的应用场景。

@Service(Scope="singleton")
public class SingletonServiceImpl implements SingletonService{
    @Resource
    PrototypeBean prototypeBean;//直接在单例模式中注入原型bean,prototypeBean其实只实例化了一次,原型模式的作用完全没有发挥
    public void start(){
        prototypeBean.setFoo(new Foo());
        prototypeBean.setBar(new Bar());
        process(prototypeBean);

    }
    public void process(PrototypeBean prototypeBean){
        //......
    }
}
@Service(Scope="prototype")
public class PrototypeBean{
    private int count = 0;
    private Foo foo;
    private Bar bar;
    public void setFoo(Foo foo){
        this.foo = foo;
        count = count+1;
        System.out.println(count);
    }
    public void setBar(Bar bar){
        this.bar = bar;
        count = count+1;
        System.out.println(count);
    }
}

现在的目标是每次调用start方法,都会实例化一个新的prototypeBean,有如下几种方案:
1.放弃部分ioc能力,手动调用getBean方法(代码中会出现spring相关依赖代码,不推荐):

@Service(Scope="singleton")
public class SingletonServiceImpl implements SingletonService,ApplicationContextAware{
    ApplicationContext applicationContext;
    public void start(){
        PrototypeBean prototypeBean = applicationContext.getBean("prototypeBean",PrototypeBean.class);
        prototypeBean.setFoo(new Foo());//output 1
        prototypeBean.setBar(new Bar());//output 2
        process(prototypeBean);

    }
    public void process(PrototypeBean prototypeBean){
        //......
    }
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
   }
}

2.lookup方法注入
该方法利用cglib动态生成一个SingletonServiceImpl的子类,该子类会自动override有lookup注解的方法,代码干净整洁。

@Service(Scope="singleton")
public class SingletonServiceImpl implements SingletonService{

    public void start(){
        PrototypeBean prototypeBean = this.createPrototypeBean();
        prototypeBean.setFoo(new Foo());//output 1
        prototypeBean.setBar(new Bar());//output 2
        process(prototypeBean);

    @Lookup 
    public PrototypeBean createPrototypeBean(){
        return null;//该方法会被cglib自动重写,所以直接返回null就可以。注意方法不能是private,否则cglib不能继承该方法
    }
    public void process(PrototypeBean prototypeBean){
        //......
    }

3.使用动态代理
spring提供了动态代理,在注入PrototypeBean时会先注入一个PrototypeBean的代理类,等方法调用时,由代理类分配具体的实例,还是先看代码:

@Service(Scope="singleton")
public class SingletonServiceImpl implements SingletonService{
    @Resource
    PrototypeBean prototypeBean;

    public void start(){
        prototypeBean.setFoo(new Foo());
        prototypeBean.setBar(new Bar());
        process(prototypeBean);

    }
    public void process(PrototypeBean prototypeBean){
        //......
    }
}
//如果是接口,就使用ScopeProxyMode.INTERFACES
@Service(Scope="request",proxyMode=ScopeProxyMode.TARGET_CLASS)
public class PrototypeBean{
    private int count = 0;
    private Foo foo;
    private Bar bar;
    public void setFoo(Foo foo){
        this.foo = foo;
        count = count+1;
        System.out.println(count);
    }
    public void setBar(Bar bar){
        this.bar = bar;
        count = count+1;
        System.out.println(count);
    }
}

重点来了,请注意PrototypeBean的注解中,scope我使用了request。为什么不使用prototype呢,因为在动态代理时,如果使用prototype,对prototypeBean中方法的每一次调用,都会生成一个新的prototypeBean实例,如果scope使用prototype,则会出现下面的情况:

public void start(){
        prototypeBean.setFoo(new Foo());//output 1
        prototypeBean.setBar(new Bar());//output 1此时的prototypeBean与上面一行的prototypeBean是两个实例,这样违背了我们希望在start中得到一个新实例的初衷。
        process(prototypeBean);

    }

由于我主要是参考了spring的官方文档和自己构造案例测试,并没有阅读源码。有不对之处欢迎大家指出~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值