Java 单例对象初始化和依赖项注入

Java 单例对象初始化和依赖项注入,java,singleton,Java,Singleton,我通常使用singleton holder模式创建singleton类,如下所示: public class Foo { private static final class SingletonHolder { private static final Foo INSTANCE = new Foo(); } private Foo(){} public static final Foo getInstance(){ ret

我通常使用singleton holder模式创建singleton类,如下所示:

public class Foo {

    private static final class SingletonHolder {
        private static final Foo INSTANCE = new Foo();
    }  

    private Foo(){}

    public static final Foo getInstance(){
        return SingletonHolder.INSTANCE;
    }

}
一切都好。但是,如果我需要注入一个依赖项来初始化singleton对象呢

在这种情况下,我添加了一个方法
initialize
,该方法接收依赖项,并且只能调用一次:

public class Foo {

    private static final class SingletonHolder {
        private static final Foo INSTANCE = new Foo();
    }  

    private Foo(){}

    public static final void initialize(Dependency d) {
        SingletonHolder.INSTANCE.setDependency(d);
    }

    public static final Foo getInstance(){
        return SingletonHolder.INSTANCE;
    }

}

我这样做对吗?还有别的解决办法吗?我知道这取决于程序,我的逻辑等等。。。但是通常应该如何解决这个问题呢?

这种方法的问题是,
initialize
方法可以被多次调用,并且代码中没有任何迹象表明正在使用线程安全性处理依赖项的设置

如果您不介意的话,那么您的懒惰初始化习惯用法就可以了

否则,当在单例实例中多次设置依赖项时,您可以抛出一个
IllegalStateException
,或者不做任何事情

编辑


如上所述,您也没有检查在调用
getInstance
之前是否设置了依赖项,或者至少您的代码没有显示它

我认为你把它复杂化了。在我工作过的一些地方(包括我现在工作的地方),我们不试图强制执行单身。实际应用程序的所有布线都在一个地方完成,因此如果您搜索构造函数的用法,您应该在
src
中找到一个,在
test
中可能找到多个。请参阅下面的代码

您的方法有几个缺点:

  • 你失去了不变性,
    Foo
    的依赖关系可以改变
  • setDependency
    initialize
    方法都是生产中的测试代码
  • 您的构造函数没有创建有效的对象,构造函数的另一半在
    initialize
    方法中,您必须记住在调用构造函数后调用该方法
  • SingletonHolder
    是一个锅炉板代码,我不确定您为什么不声明
    public static final Foo instance
    字段
  • 仍然可以使用反射API和对象序列化机制创建
    Foo
    的多个实例

此外,在第一次调用
Foo.getInstance()
之前,可能根本没有调用
initialize()
方法。为什么不创建一个实例并传递它,而不是使用单例呢?
public class Foo {

    private final Dependency dependency;

    public Foo(Dependency dependency) {
        this.dependency = dependency;
    }

    // ...
}

public class Dependency {
    // ...
}