使单例成为Spring bean的正确方法

rk2*_*010 20 java singleton spring

我正在将单例转换为Spring bean,因此如果单例无法初始化,则整个Web应用程序的spring上下文无法正确加载.

使Spring上下文无法正确加载的优点是人们会在部署期间注意并修复配置.与使用'非spring bean'单例相反:当在初始化期间抛出异常时,没有人注意到......直到实际用户抱怨缺少功能.

我的更改正在按预期工作..但我不确定我是否正在做正确的事情.
有什么想法吗?

代码如下所示:

public class MySingleton {

    private static MySingleton INSTANCE = null;
    private MySingleton(){}


public static MySingleton getInstance(){
    if(INSTANCE == null){
        synchronized(MySingleton.class){
            if(INSTANCE == null){
                try{
                    doWork()
                }catch(Exception e){
                    throw new IllegalStateException("xyz", e);
                }
                INSTANCE = new MySingleton();
            }
        }
    }

    return INSTANCE;
}

private static void doWork() {
    // do some work
    }

}
Run Code Online (Sandbox Code Playgroud)

在spring config xml中,bean将被定义为:

<bean id="MySingletonBean"
    class="com.MySingleton"
    factory-method="getInstance" lazy-init="false" singleton="true">
</bean>
Run Code Online (Sandbox Code Playgroud)

注意: 大部分内容类似于本文中讨论的策略:http: //springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html


编辑1:

使用这个单例的类不是spring bean本身..它们只是非春天的pojos,我无法转换为spring.他们必须依靠getInstance()方法来获取Singleton.


编辑2 :(将我在下面的评论复制到此描述部分)我试图针对两件事:

  1. 我希望Spring初始化单例.因此,如果初始化失败,则应用程序加载失败.
  2. 我希望其他类能够使用类而不必依赖contextAwareObj.getBean("MySingleton")


编辑3(最后): 我决定让这个班级成为一个单身人士......而不是让它成为一个春天的豆子.如果它无法初始化,它将在日志文件中记录一些内容..希望进行部署的人注意到....我放弃了我之前提到的方法,因为我觉得它将来会造成维护噩梦,所以我不得不选择 - 单身 - 或 - 春豆.我选择了单身人士.

Mat*_*all 19

必须将该INSTANCE字段声明volatile为双重检查锁定才能正常工作.

请参阅Effective Java,Item 71.


Tom*_*icz 13

为什么你首先使用单身模式?让Spring为你创建bean(使用默认singleton范围)并使用它.当然总是有人可能会手工制作豆子,但在我的情况下这绝不是问题.

依赖注入和Spring管理的bean生命周期将显着减轻您的生活(只需看看您可以避免多少陷阱).另请注意,从c-tor或@PostContruct方法抛出的异常将传播并导致应用程序上下文启动失败.

更新:我明白你的观点.这就是我的想法:

@Service
public class Singleton {

    private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();

    public Singleton() {
        final Singleton previous = INSTANCE.getAndSet(this);
        if(previous != null)
            throw new IllegalStateException("Second singleton " + this + " created after " + previous);
    }

    public static Singleton getInstance() {
        return INSTANCE.get();
    }

}
Run Code Online (Sandbox Code Playgroud)

让Spring做好自己的工作.您可以尽可能使用DI,也可以Singleton.getInstance()在必要时使用.

还有更多的核心解决方案,如编译时AspectJ编织和基本上将Spring bean注入所有内容.


Rod*_*zel 6

我不确定你为什么要这样做.当你告诉Spring一个bean应该是一个单例时,相应的类不需要是一个单独的,也不需要工厂.Spring只是简单地创建一个实例.

链接的文章对我没有意义,因为没有注入发生,我可以看到:"AnyService"调用单例工厂方法; 应用程序上下文中引用单例在引用之前是无关紧要的,似乎没有其他bean引用它.


Den*_*nis 5

真正的单身人士很难开始工作.

挥发性双重检查锁定也不起作用.在维基http://en.wikipedia.org/wiki/Double-checked_locking上阅读它

你最好的选择就是这么做

public class MySingleton {

    private static MySingleton INSTANCE = new MySingleton();
Run Code Online (Sandbox Code Playgroud)

也就是说,如果您的实际代码中没有任何构造函数参数.