1

通常说只选择那些没有状态的bean作为单例。我是 Spring 新手,正在阅读 Spring 中的 bean 范围。

我的第一个问题是这个状态对于 Bean 的实际含义是什么?

其次,为什么建议使用只有无状态 bean 的单例范围?是否有一些与线程安全相关的限制或是否有任何其他原因?

4

3 回答 3

2

类的任何成员属性都称为其状态。

没有可变状态的类最适合成为 Spring(单例)bean。 可变状态是指在构造对象之后可以为其分配新值的那些成员属性。

像 DAO 这样具有 JpaRespository 等成员属性的 Bean 可以被认为具有相当不可变的状态,因为一旦 DAO 对象被初始化,就没有人为 JpaRespository 属性分配新值。

只有没有状态(没有成员属性)或具有不可变状态(成员变量的值一旦被赋值就不会更新)的 bean 才是成为 Spring bean 的理想候选者。这是因为大多数 Spring bean 都配置为 Singleton bean,并由容器中的多个线程使用。想象一下,如果您有可变状态并且多个线程试图更新单例 bean 的状态,您将永远不会有可预测的结果。

如果您的 bean 不是 Singleton,而是 Prototype bean,那么该 bean 可以具有状态,因为此类 bean 是根据需要创建和销毁的。

于 2013-07-02T10:27:07.730 回答
0

您希望在哪种对象状态下运行程序。当您设计和编写您的类时,您不知道客户是否将其用作单例或原型。容器配置对象。因此,它可能是单例或原型。例如Spring 框架的TransactionAwareDataSourceProxy 类被编写为在原型或单例中运行。该类的编写方式使其免受多线程访问的影响。作为状态由所有线程共享的,通过DI容器通过一些setter方法变得通用。因此,作为单例的配置是在启动时通过容器进行的,它的公共值被所有线程或单线程使用。实例变量的设置只进行一次用一些setter方法。例如在类 TransactionAwareDataSourceProxy 中有reobtainTransactionalConnections作为实例变量。

public TransactionAwareDataSourceProxy()
    {
        reobtainTransactionalConnections = false;
    }

    public TransactionAwareDataSourceProxy(DataSource targetDataSource)
    {
        super(targetDataSource);
        reobtainTransactionalConnections = false;
    }
    public void setReobtainTransactionalConnections(boolean reobtainTransactionalConnections)
    {
        this.reobtainTransactionalConnections = reobtainTransactionalConnections;
    }

这些是代码中reobtainTransactionalConnections被初始化的地方。如果您决定通过 DI 容器创建此类单例,您可以使用构造函数注入或 setter 注入设置一次。因此,如果我们进行 setter 注入,那么 setReobtainTransactionalConnections 将是 true 或 false 并且在整个对象生命周期中保持不变。我认为这就是使用容器配置对象的优点,可以轻松进行对象状态控制

于 2013-07-02T09:41:16.153 回答
0

如果对方法的调用不仅取决于为方法调用提供的参数,而且还取决于先前的调用,则对象(并且 bean 是对象)具有状态。

原则上,如果您有任何实例变量,您可能有一个状态。唯一的例外是存储在实例(不是static)变量中的单例(这在 Spring 编程中很常见)不计入状态。

在使用多线程环境时,单例中的状态可能会产生副作用。例如,一个线程设置状态(例如要打开的连接),而另一个线程不期望这种状态。然后一个线程可能会失败。

于 2013-07-02T07:10:22.750 回答