Java 向单例类注入依赖项
我有一个定义如下的单例实例:Java 向单例类注入依赖项,java,dependency-injection,singleton,Java,Dependency Injection,Singleton,我有一个定义如下的单例实例: public class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() { } public Singleton getInstance() { return INSTANCE; } } 现在,由于一些变化,这个类必须依赖于几个(3)依赖项。因此,这些依赖关系必须在这里注入 我们如
public class Singleton {
private static Singleton INSTANCE = new Singleton();
private Singleton() {
}
public Singleton getInstance() {
return INSTANCE;
}
}
现在,由于一些变化,这个类必须依赖于几个(3)依赖项。因此,这些依赖关系必须在这里注入
我们如何为这样设计的单例类实现依赖注入
问题是,Singleton.getInstance()
上已经有很多调用者,因此无法使getInstance方法接受依赖项
附言:我明白使用单例并不总是一种更干净的方式:)
(这是现有的代码,我不得不接受它:))
附言:我正在使用Guice进行依赖注入。你可以这样做
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 bean注入单例bean的示例:
您可以将类重构为依赖项,同时为客户端保留相同的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
从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;
}
}
您可以在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;
}
...
}
如果使用Spring,即使没有公共构造函数,也可以实现依赖项注入。只需将依赖项标记为@Autowired。Spring将通过反射注入它们。:) 您正在使用哪个依赖注入框架?或者您必须能够通过静态方法使依赖项可用;或者,您必须咬紧牙关,使用guice@AndyTurner你说我通过静态方法提供依赖项到底是什么意思?无论如何,当客户端调用静态getInstance()时,其他依赖项将保持未初始化状态。请编辑问题以指定这是一个GUI应用程序。这样做没有多大意义:您只是在许多地方重复
DependencyClass1 dependency1
<代码>私有DependencyClass1=新DependencyClass1(…);/*…*/INSTANCE=newsingleton()是等效的且更短。不幸的是,我不能这样做,因为我不能硬代码一个具体的依赖项,因为它必须被注入。我认为非默认构造函数显然表明这个类依赖于其他一些类。但这需要更改所有客户端(因为它们调用静态getInstance方法)。我想知道除了使singleton类成为一个普通的依赖项/classI之外,是否还有其他方法可以实现这一点。我假设它不应该是一个重要的重构(用singleton.getInstance()替换singleton.getInstance()
)
。具有静态访问权限的singleton很难成为依赖项。静态和依赖项注入根本不以相同的方式工作。我同意你的观点。因此,你说如果不改变客户端调用它的方式,就无法使用这样的静态方法将可注入依赖项添加到这样的singleton类中(这里单例本身必须传递/注入到每个客户机)?我不是说这是不可能的,但这将是一种违反直觉且容易出错的方法。我对此进行了编辑。它在Spring中完成,以与我最初的答案保持一致,但您可以对Guice执行完全相同的操作。