单例中的弹簧原型范围豆

2022-09-01 11:38:46

我正在尝试在Bean中注入bean,以便对单例Bean方法的每个新调用都有一个原型Bean的新实例。prototypesingleton

考虑一个单例豆,如下所示:

    @Component
    public class SingletonBean {
       @Autowired 
       private PrototypeBean prototypeBean;

       public void doSomething() {
         prototypeBean.setX(1);
         prototypeBean.display();
       }
    }

我希望每次调用该方法时,都会使用一个新实例。doSomething()PrototypeBean

下面是原型豆:

     @Component 
     @Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
     public class PrototypeBean {
        Integer x;

        void setX(Integer x) {
         this.x = x;
        }

        void display() {
          System.out.println(x);
        }
    }

似乎正在发生的事情是,Spring在方法中移交了PrototypeBean的新实例时过于急切。也就是说,该方法中的 2 行代码将在每行中创建一个新的 prototypeBean 实例。doSomething()doSomething()

因此,在第二行中 - 打印 NULLprototypeBean.display()

此注入的配置中缺少哪些内容?


答案 1

来自春季文档

您不需要将 与作用域为单例或原型的 Bean 结合使用。如果尝试为单例 Bean 创建作用域代理,则会引发 BeanCreationException。<aop:scoped-proxy/>

对于3.2版文档,文档似乎发生了一些变化,您可以在其中找到以下句子:

您不需要将 与作用域为单例或原型的 Bean 结合使用。<aop:scoped-proxy/>

似乎您没有期望使用代理原型bean,因为每次请求它时,它都会创建一个新的实例。BeanFactory


为了给你的原型豆建立一种工厂,你可以使用如下:ObjectFactory

@Component
public class SingletonBean {

    @Autowired
    private ObjectFactory<PrototypeBean> prototypeFactory;

    public void doSomething() {
        PrototypeBean prototypeBean = prototypeFactory.getObject();
        prototypeBean.setX(1);
        prototypeBean.display();
    }
}

并且您的原型 Bean 将声明如下:

@Component 
@Scope(value="prototype")
public class PrototypeBean {
    // ...
}

答案 2

单例 Bean 只创建一次,因此注入的原型 Bean 也将在单例 Bean 的实例化时创建一次。原型 Bean 的相同实例将用于每个请求。

如果在运行时为每个请求创建原型bean的新实例,则可以使用以下方法注入

public class Singleton {
    private Prototype prototype;

    public Singleton(Prototype prototype) {
        this.prototype = prototype;
    }

    public void doSomething() {
         prototype.foo();
    }

    public void doSomethingElse() {
        prototype.bar();
    }
}

public abstract class Singleton {
    protected abstract Prototype createPrototype();

    public void doSomething() {
        createPrototype().foo();
    }

    public void doSomethingElse() {
        createPrototype().bar();
    }
}


<bean id="prototype" class="ch.frankel.blog.Prototype" scope="prototype" />
<bean id="singleton" class="sample.MySingleton">
   <lookup-method name="createPrototype" bean="prototype" />
</bean>

推荐