问题 Spring注入一个静态(全局)单例


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

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(或类似的东西):

<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",或者这不重要吗?我正确设置静态属性吗?我还需要做什么或考虑一下吗?提前致谢。


8879
2018-02-01 11:11


起源



答案:


Singleton作为设计模式与Spring的单身设施有一些区别。 Singleton作为设计模式将确保每个Class Loader定义一个类对象。相比之下,Spring的单例工具(和方法)将为每个Spring Context定义一个实例。

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

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

随着春天 singleton bean范围是默认值,因此您无需定义它。

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

我也看到你在设计你的单身人士时遇到了错误。你的 getInstance() 方法应该是公共的,其他方法不应该是静态的。在您使用的示例中,您应该像这样使用Singleton:

Configurator.getInstance().someMethod()

在这种情况下,您实际上只使用Singleton类,而无需实例化任何对象!看到 Singleton上的维基百科(附Java示例) 有关Singleton设计模式以及如何使用它的更多信息。


注意:值得了解并尝试使用 Configurator 作为一个单身人士并使用Spring的单身人士设施。如果你这样做,你可以获得好处

  • 去除 getInstance() 方法
  • 让你的构造函数公开
  • 让Spring实例化那个单个对象。

9
2018-02-01 11:25



谢谢@partlov(+1) - 我需要制作我的 getInstance() 方法public,还是Spring可以处理它私有的事实?
你不需要它(getInstance()) - Bob Flannigon


答案:


Singleton作为设计模式与Spring的单身设施有一些区别。 Singleton作为设计模式将确保每个Class Loader定义一个类对象。相比之下,Spring的单例工具(和方法)将为每个Spring Context定义一个实例。

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

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

随着春天 singleton bean范围是默认值,因此您无需定义它。

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

我也看到你在设计你的单身人士时遇到了错误。你的 getInstance() 方法应该是公共的,其他方法不应该是静态的。在您使用的示例中,您应该像这样使用Singleton:

Configurator.getInstance().someMethod()

在这种情况下,您实际上只使用Singleton类,而无需实例化任何对象!看到 Singleton上的维基百科(附Java示例) 有关Singleton设计模式以及如何使用它的更多信息。


注意:值得了解并尝试使用 Configurator 作为一个单身人士并使用Spring的单身人士设施。如果你这样做,你可以获得好处

  • 去除 getInstance() 方法
  • 让你的构造函数公开
  • 让Spring实例化那个单个对象。

9
2018-02-01 11:25



谢谢@partlov(+1) - 我需要制作我的 getInstance() 方法public,还是Spring可以处理它私有的事实?
你不需要它(getInstance()) - Bob Flannigon


豆是默认的单身。您可以通过spring网站找到这个/更多信息。

你不应该在getInstance中实例化一个新的Configurator,因为它不会引用spring加载的bean,这可能会导致一些严重的问题。您可以将此bean连接起来然后不管它,它不会为空,因为您已将其连接(如果您的程序将初始化失败)。


1
2018-02-01 11:15





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

  1. spring中的默认范围是singleton,因此您不需要 显式地将bean设置为单例范围。
  2. 使用Spring,您不需要编写 单身人士模式 样式代码,例如私有实例和工厂方法。那是因为春天会 保证每个Spring只有一个实例 容器。甚至没有说,你的工厂方法是私人的。

0
2018-02-01 11:21





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

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


0
2017-10-11 11:23