使单例成为春豆的正确方法

2022-09-02 02:45:47

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

使Spring上下文无法正确加载的好处是,人们将在部署过程中注意到并修复配置。与使用“非弹簧豆”单例相反:当在初始化期间引发异常时,没有人会注意到。直到实际用户抱怨缺少功能。

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

代码如下所示:

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
    }

}

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

<bean id="MySingletonBean"
    class="com.MySingleton"
    factory-method="getInstance" lazy-init="false" singleton="true">
</bean>

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


编辑 1:

使用此单例的类不是弹簧豆本身。他们只是非春天的pojos,我无法转换为春天。他们必须依靠 getInstance() 方法获取 Singleton。


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

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


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

答案 1

您必须将字段声明为双重检查锁定才能正常工作。INSTANCEvolatile

《有效Java》,第71项


答案 2

为什么一开始就使用单例模式?只需让Spring为您创建豆子(具有默认范围)并...使用它。当然,总会有人手工制作豆子,但在我的情况下,这从来都不是问题。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();
    }

}

让春天做它的工作。您可以在可能的情况下和必须使用 DI。Singleton.getInstance()

还有更多的硬核解决方案,如编译时AspectJ编织和注入弹簧豆基本上到一切。


推荐