有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我通常使用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;
    }

}

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


共 (2) 个答案

  1. # 1 楼答案

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

    您的方法有几个缺点:

    • 如果失去了不变性,Foo的依赖关系可以改变
    • setDependencyinitialize方法都是生产中的测试代码
    • 您的构造函数没有创建有效的对象,构造函数的另一半在initialize方法中,您必须记住在调用构造函数后调用该方法
    • SingletonHolder是一个锅炉板代码,我不确定您为什么不直接声明public static final Foo instance字段
    • 仍然可以使用反射API和对象序列化机制创建Foo的多个实例
    public class Foo {
    
        private final Dependency dependency;
    
        public Foo(Dependency dependency) {
            this.dependency = dependency;
        }
    
        // ...
    }
    
    public class Dependency {
        // ...
    }
    
  2. # 2 楼答案

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

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

    否则,您可以抛出一个IllegalStateException,或者在单例实例中多次设置依赖项时不执行任何操作

    编辑

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