我想做一个添加用户的服务,这个服务里面有一个属性就是那个待添加的用户。
每次运行这个服务的时候我发现虽然在配置文件里面用户的bean定义的是prototype但是由于服务的bean是singleton所以致使他的这个属性也有了singleton的行为,该怎么办呢?

解决方案 »

  1.   

    你是不是引用了多个context上下文,或者不在同一个线程里面?
      

  2.   

    设置singleton属性为false应该就可以了
      

  3.   

    不太明白楼主的说法像是一种可传递的单例特性?不过,楼主可以在任何一层自己写一个getInstance方法去覆盖Spring的默认单例行为
      

  4.   

    把你的service设置成scope="prototype"
    另外:有状态的对象一般不要被注入
      

  5.   

    将singleton设为false,那每次请求的时候都会产生一个新的实例为你服务
      

  6.   

    在大部分情况下,容器中的bean都是singleton类型的。如果一个singleton bean要引用另外一个singleton bean,或者一个非singleton bean要引用另外一个非singleton bean时,通常情况下将一个bean定义为另一个bean的property值就可以了。不过对于具有不同生命周期的bean来说这样做就会有问题了,比如在调用一个singleton类型bean A的某个方法时,需要引用另一个非singleton(prototype)类型的bean B,对于bean A来说,容器只会创建一次,这样就没法在需要的时候每次让容器为bean A提供一个新的的bean B实例。上述问题的一个解决办法就是放弃控制反转。通过实现BeanFactoryAware接口,让bean A能够感知bean 容器,并且在需要的时候通过使用getBean("B")方式向容器请求一个新的bean B实例。不过该做法绝非上策,因为这样bean的代码将与Spring藕合在了一起
      

  7.   

    人家楼主说像通过一个singleton得到一个prototype, 这样设计肯定有他的原因, 你们让他改成singleton=false不是违背了人家的意思么?
    陈雄华的书第110页给得例子, lookup-method就是用来解决这个问题的。我专门作了测试类,
    User:表示User对象, 为了显示出它是个prototype的,我专门加了一个无意义的Date属性;public class User{

    private String username;
    private String password;
    private Date date = new Date();

    public String getPassword() {
    return password;
    }
    public void setPassword(String password) {
    this.password = password;
    }
    public String getUsername() {
    return username;
    }
    public void setUsername(String username) {
    this.username = username;
    }

    public String toString(){
    return "\nUsername: " + username +" Password: " + password + " Date: " + date;
    }

    public Date getDate() {
    return date;
    }
    public void setDate(Date date) {
    this.date = date;
    }

    }Service:public abstract class Service { private User user; public abstract User getUser(); public void setUser(User user) {
    this.user = user;
    }

    public void addUser(){
    System.out.println("A user [" + getUser().toString() +  "] will be added in.");
    }}这里有个abstract方法, 将通过bean 配置文件的lookup标签来解决这个方法得返回值问题。
    配置文件: <bean id="user" class="test.User" scope="prototype">
    <property name="username" value="username"/>
    <property name="password" value="password"/>
    </bean>

    <bean id="service" class="test.Service">
    <!--property name="user" ref="user"/-->
    <lookup-method name="getUser" bean="user" />
    </bean>测试文件:public class Test { public static void main(String[] args) throws ParseException, ServletException, IOException {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("test-bean.xml");
    Service s = (Service)ctx.getBean("service");
    s.addUser();
    try {
    Thread.sleep(1000);//睡一觉,以便结果更明显;
    } catch (InterruptedException e) {
    }
    Service s1 = (Service)ctx.getBean("service");
    s1.addUser();
           }
    }输出结果:
    A user [
    Username: username Password: password Date: Fri Nov 14 15:22:02 CST 2008] will be added in.
    A user [
    Username: username Password: password Date: Fri Nov 14 15:22:03 CST 2008] will be added in.
      

  8.   

     还有一点我疏忽了,
    Service可以不是abstract的,
    getUser()也可以不是abstract的,<lookup-method name="getUser" bean="user" />这句话spring将通过动态代理修改getUser()方法。
      

  9.   

    对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)