2.5 协调作用域不同步的Bean

在Spring容器中,最常见的为singleton与prototype作用域的Bean,当我们多次获取singleton作用域的Bean时,得到的都是同一个实例,而prototype作用域里则每次都产生一个新的Bean实例。我们知道,Spring容器在初始化某个Bean前,先会创建被依赖的Bean,然后再对该Bean进行初始化,如果此时为singleton作用域的Bean依赖prototype作用域的Bean,由于singleton作用域的Bean只初始化一次,故prototype作用域的Bean也只被注入一次,之后我们每次通过singleton Bean去访问prototype Bean时,得到的永远是最初的那个prototype Bean,也可以理解为singleton Bean把它所依赖的prototype Bean变成了singleton,这就违背了我们设置prototype Bean的初衷。

有以下两种解决思路:

  • 不使用依赖注入,当singleton 作用域的Bean每次需要prototype作用域的Bean是,主动向容器请求新的Bean实例。
  • 使用lookup方法注入

不建议使用第一种方法,因为此做法会导致程序代码与Spring API耦合,造成代码污染。使用lookup方法注入可以让Spring容器重写容器中调用者Bean的抽象或具体方法,返回查找容器中其他Bean的结果。为了使用lookup方法注入,大致需要如下两步

  • 将调用者Bean的实现类定义为抽象类,并定义一个抽象方法来获取被依赖的Bean
  • <bean.../>元素中添加<lookup-method.../>子元素让Spring为调用者Bean的实现类实现指定的抽象方法

以下给出demo:

beans.xml部分代码

 <bean id="chinese" class="spring实例.Chinese" >
        <!--name:指定需要让Spring实现的方法;bean:指定该方法的返回值-->
        <!-- Spring只要检测到lookup-method元素,会自动为该元素的name属性所指定的方法提供实现体 -->
        <!--实现getDog()方法,返回id="dog"的Bean-->
        <lookup-method name="getDog" bean="dog"/>
 </bean>
 <!--设置作用域为prototype的Bean-->
 <bean id="dog" class="spring实例.Dog" scope="prototype">
        <property name="name" value="柯基"></property>
 </bean>

定义调用者Bean的实现类Chinese类为抽象类,并定义抽象方法getDog()

public abstract class Chinese implements Person {
    private Dog dog;
    public abstract Dog getDog();
    public void hunt(){
        System.out.println("我带着ID为:"+getDog()+"出去打猎");
        getDog().run();
    }
}

Dog类

public class Dog {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void run(){
        System.out.println("名为["+getName()+"]的小狗不要命地跑!");
    }
}

主程序部分代码

ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
Chinese c=ctx.getBean("chinese", Chinese.class);
c.hunt();
c.hunt();

运行结果
我带着ID为:spring实例.Dog@1b279c9出去打猎
名为[柯基]的小狗不要命地跑!
我带着ID为:spring实例.Dog@d282e0出去打猎
名为[柯基]的小狗不要命地跑!

运行结果显示,每次通过Chinese实例调用getDog()方法,都会返回新的Dog实例。这里补充一下,实质上Spring实现方法的逻辑是固定的,如下代码:

public Dog getDog(){
    //获取Spring容器ctx
    ...
    //返回值
    return ctx.getBean("Dog");
}

猜你喜欢

转载自blog.csdn.net/gd_hacker/article/details/77750300
2.5