将依赖项注入Singleton类

时间:2017-12-22 09:39:44

标签: java dependency-injection singleton

我有一个像这样定义的单例实例:

public class Singleton {
    private static Singleton INSTANCE = new Singleton();

    private Singleton() {

    }

    public Singleton getInstance() {
        return INSTANCE;
    }
}

现在,由于一些更改,此类必须依赖于一些(3)依赖项。因此,这些依赖关系必须注入

我们如何为这样设计的Singleton类实现依赖注入?

问题是Singleton.getInstance()上已有很多调用者,因此无法使getInstance方法接受依赖项。

P.S:我明白使用单身人士并不总是更清洁的方式:) (这是现有的代码,我必须忍受它:))

P.S:我正在使用Guice进行依赖注入。

4 个答案:

答案 0 :(得分:2)

您可以将您的类重构为依赖项,同时为客户端保留相同的API 以Spring为例:

@Component
public class Singleton {

  private Foo foo;
  private Bar bar;
  private Any any;

  // inject dependencies 
  @Autowired
  // annotation not required in recent Spring versions
  public Singleton (Foo foo, Bar bar, Any any){
     this.foo = foo;
     this.bar = bar;
     this.any = any;
  }

  public Singleton getInstance() {
      return this;
  }
}

如果客户端类不是bean,从客户端可以注入bean或从bean容器中检索它。

从bean类访问的示例:

public class SingletonClient{

    @Autowired
    private Singleton singleton;

    public void foo(){
        singleton.getInstance().method();
    } 
}

避免客户类更改的想法 免责声明:我不会以这种方式推广,因为它既反直觉又容易出错,最重要的是保持单身人士静态访问的技术债务。
作为临时解决方案是可以接受的,但是应该尽快对现有代码进行重构。

因此,想法是在构造函数调用期间将bean实例存储在静态字段中 通过这种方式,Singleton.getInstance()返回bean。

@Component
public class Singleton {

    private Foo foo;
    private Bar bar;
    private Any any;

    private static Singleton instance;

    // inject dependencies
    @Autowired
    // annotation not required in recent Spring versions
    public Singleton(Foo foo, Bar bar, Any any) {
      this.foo = foo;
      this.bar = bar;
      this.any = any;
      instance = this;
    }

    public static Singleton getInstance() {
      return instance;
    }

}

答案 1 :(得分:0)

你可以这样做。

public class Singleton {

    private DependencyClass1 dependency1;

    private DependencyClass2 dependency2;

    private DependencyClass3 dependency3;

    private static Singleton INSTANCE = new Singleton(
            new DependencyClass1(...),
            new DependencyClass2(...),
            new DependencyClass3(...)
    );

    private Singleton(
            DependencyClass1 dependency1,
            DependencyClass2 dependency2,
            DependencyClass3 dependency3
    ) {
        this.dependency1 = dependency1;
        this.dependency2 = dependency2;
        this.dependency3 = dependency3;
    }

    public Singleton getInstance() {
        return INSTANCE;
    }
}

与任何IOC容器相同。

如果所有注入的依赖项都有单例作用域,则可以执行此操作,否则每次需要时都需要创建注入类的实例。

有注射Protype Beans进入Singleton Beans的例子:

https://stackoverflow.com/a/25165971/3058413

答案 2 :(得分:0)

您可以在Guice中使用@Singleton注释告诉注入器只创建一个在您的应用程序中共享的实例。然后,您可以通过注释变量或选择的构造函数

以通常的方式注入依赖项
    @Singleton
    public class Singleton {

      @Inject // Choose to put the annotation here OR on a constructor, not both
      private Foo foo;

      @Inject // only put this constructor here if you don't annotate the variable
      public Singleton (Foo foo){
         this.foo = foo;
      }

      public Singleton getInstance() {
          return this;
      }

...
    }

答案 3 :(得分:0)

如果您使用Spring,即使没有公共构造函数,也可以实现依赖注入。只需标记依赖关系@Autowired。 Spring将通过反射注入它们。 :)