12

我有一个看起来像这样的类:

public class Configurator {
    private static Configurator INSTANCE = null;

    private int maxRange = 1;

    // many other properties; each property has a default value

    private static synchronized Configurator getInstance() {
        if(INSTANCE == null)
            return new Configurator();

        return INSTANCE;
    }

    public static int getMaxRange() {
        getInstance().maxRange;
    }

    public static void setMaxRange(int range) {
        getInstance().maxRange = range;
    }

    // Getters and setters for all properties follow this pattern
}

它作为一个全局配置对象,可以在应用启动时设置,然后被整个项目的几十个类使用:

// Called at app startup to configure everything
public class AppRunner {
    Configurator.setMaxRange(30);
}

// Example of Configurator being used by another class
public class WidgetFactory {
    public void doSomething() {
        if(Configurator.getMaxRange() < 50)
            // do A
        else
            // do B
    }
}

我现在将此代码导入 Spring 项目,并尝试配置我的 Sprinig XML (bean)。我的猜测是我可以Configurator像这样(或类似的东西)定义一个孤豆:

<bean id="configurator" class="com.me.myapp.Configurator" scope="singleton">
    <property name="maxRange" value="30"/>
    <!-- etc., for all properties -->
</bean>

这样,当WidgetFactory#doSomething执行时,Spring 将已经加载了Configurator该类并提前对其进行了配置。

设置 对我来说是否正确scope="singleton",或者这无关紧要?我是否正确设置了静态属性?还有什么我需要做或考虑的吗?提前致谢。

4

4 回答 4

11

作为一种设计模式的单例与 Spring 的单例设施之间存在一些差异。单例作为一种设计模式将确保您为每个类加载器定义一个类对象。相比之下,Spring 的单例工具(和方法)将为每个 Spring Context 定义一个实例。

在这种情况下,您可以利用getInstance()Spring 使用的方法来获取对象实例:

<bean id="configurator" class="com.me.myapp.Configurator" factory-method="getInstance">
</bean>

使用 Spring,singletonbean 范围是默认的,因此您不需要定义它。

如果您想configurator用作 Spring bean,则必须将其注入其他对象,而不是getInstance()用来抓取它。所以在其他 Spring bean 中使用 @Autowired 或通过 xml 文件定义对 bean 的引用。如果你不重新组织configurator其他类中的用法,没有区别,Spring会实例化你的类,但你会像以前一样使用它。

我还看到您在设计单例时有错误。你的getInstance()方法应该是公开的,其他方法不应该是静态的。在您使用的示例中,您应该像这样使用 Singleton:

Configurator.getInstance().someMethod()

在这种情况下,您实际上只是使用 Singleton 类,而不实例化任何对象!有关Singleton 设计模式以及如何使用它的更多信息,请参阅关于 Singleton 的 wikipedia(带有 Java 示例) 。


注意:值得了解并尝试将其Configurator用作单例并使用 Spring 的单例工具。如果你这样做,好处是你可以

  • 删除getInstance()方法
  • 公开你的构造函数
  • 让 Spring 实例化该单个对象。
于 2013-02-01T11:25:05.240 回答
2

默认情况下,bean 是单例的。您可以通过 spring 网站找到此/更多信息。

您不应该在 getInstance 中实例化新的配置器,因为它不会引用弹簧加载的 bean,这可能会导致一些严重的问题。您可以连接这个 bean,然后不理会它,它不会为空,因为您已经连接了它(如果是,您的程序将无法初始化)。

于 2013-02-01T11:15:50.840 回答
0

是的,如果你想要一些全局的东西,单例范围是正确的选择。这里值得一提的是:

  1. spring 的默认作用域是单例的,所以你不需要显式地将你的 bean 设置为单例作用域。
  2. 使用 Spring,您无需编写单例模式样式代码,例如私有实例和工厂方法。这是因为 Spring 将保证每个 Spring 容器只有一个实例。更不用说,你的工厂方法是私有的。
于 2013-02-01T11:21:08.013 回答
0

顺便说一句:这不是线程安全的:

if(INSTANCE == null)
        return new Configurator();

    return INSTANCE;
}

而这将是:

private static Configurator INSTANCE = new Configurator();

(急切初始化)

private static volatile Singleton _instance = null;

(使用 volatile 关键字进行延迟初始化)

它与 Java 分配内存和创建实例的方式有关。这不是原子的,而是分两步完成的,并且可能会受到线程调度程序的干扰。

另请参阅http://regrecall.blogspot.de/2012/05/java-singleton-pattern-thread-safe.html

于 2015-10-11T11:23:52.393 回答