在 java-spring 网络应用程序中,我希望能够动态注入 bean。例如,我有一个具有 2 种不同实现的接口:
在我的应用程序中,我使用一些属性文件来配置注入:
#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA
我的注入实际上是根据属性文件中的属性值有条件地加载的。例如,在这种情况下,myinterface.type=implA 在我注入 MyInterface 的任何地方,将注入的实现将是 ImplA(我通过扩展 Conditional annotation 实现了这一点)。
我希望在运行时 - 一旦更改属性,将发生以下情况(无需重新启动服务器):
- 将注入正确的实现。例如,当设置
myinterface.type=implB
ImplB 将被注入到任何使用 MyInterface 的地方 - 应使用新值刷新 Spring 环境 并重新注入 bean。
我想刷新我的上下文,但这会产生问题。我想也许可以使用 setters 进行注入,并在重新配置属性后重新使用这些 setters。是否有针对此类要求的工作实践?
有任何想法吗?
更新
正如一些人所建议的那样,我可以使用一个工厂/注册表来保存这两种实现(ImplA 和 ImplB)并通过查询相关属性返回正确的实现。如果我这样做,我还有第二个挑战——环境。例如,如果我的注册表如下所示:
@Service
public class MyRegistry {
private String configurationValue;
private final MyInterface implA;
private final MyInterface implB;
@Inject
public MyRegistry(Environmant env, MyInterface implA, MyInterface ImplB) {
this.implA = implA;
this.implB = implB;
this.configurationValue = env.getProperty("myinterface.type");
}
public MyInterface getMyInterface() {
switch(configurationValue) {
case "implA":
return implA;
case "implB":
return implB;
}
}
}
一旦属性发生变化,我应该重新注入我的环境。有什么建议吗?
我知道我可以在方法中查询 env 而不是构造函数,但这是一种性能降低,而且我想考虑一个用于重新注入环境的 ider(同样,也许使用 setter 注入?)。
原文由 forhas 发布,翻译遵循 CC BY-SA 4.0 许可协议
我会让这个任务尽可能简单。与其在启动时有条件地加载
MyInterface
接口的一个实现,然后触发触发动态加载同一接口的另一个实现的事件,我将以不同的方式解决这个问题,这更简单实施和维护。首先,我只加载所有可能的实现:
这个 bean 只是
MyInterface
接口的所有实现的持有者。这里没有什么神奇的,只是常见的 Spring 自动装配行为。现在,无论您需要注入
MyInterface
的特定实现,您都可以在接口的帮助下完成:然后,对于每个需要 通知 实现更改的类,只需使其实现
MyInterfaceReloader
接口即可。例如:最后,您需要一个 bean,它实际上更改了每个具有
MyInterface
作为属性的 bean 中的实现:这简单地自动装配所有实现
MyInterfaceReloader
接口的 beans 并使用新实现更新它们中的每一个,新实现从 holder 中检索并作为参数传递。同样,常见的 Spring 自动装配规则。每当您想要更改实现时,您应该只调用
updateImplementations
方法,并使用新实现的 bean 的名称,这是类的小驼峰简单名称,即myImplA
或myImplB
类MyImplA
和MyImplB
。您还应该在启动时调用此方法,以便在每个实现
MyInterfaceReloader
接口的 bean 上设置初始实现。