动态注入spring bean [英] Inject spring bean dynamically

查看:132
本文介绍了动态注入spring bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在java-spring网络应用程序中,我希望能够动态注入bean。
例如,我有一个具有2种不同实现的接口:

In a java-spring web-app I would like to be able to dynamically inject beans. For example I have an interface with 2 different implementations:

在我的应用程序中,我使用一些属性文件来配置注入:

In my app I'm using some properties file to configure injections:

#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA

我的注射实际加载有条件转发在属性文件中的属性值。例如,在这种情况下myinterface.type = implA无论我在哪里注入MyInterface,将注入的实现都是ImplA(我通过扩展条件注释

My injections actually loaded conditionally relaying on the properties values in the properties file. For example in this case myinterface.type=implA wherever I inject MyInterface the implementation that will be injected will be ImplA (I accomplished that by extending the Conditional annotation).

我想要那个在运行时 - 一旦属性被更改,将发生以下情况(不重启服务器):

I would like that during runtime - once the properties are changed the following will happen (without server restart):


  1. 将注入正确的实现。例如,当设置 myinterface.type = implB 时,ImplB将被注入到使用MyInterface的地方

  2. Spring Environment 重新注入豆类。

  1. The right implementation will be injected. For example when setting myinterface.type=implB ImplB will be injected where-ever MyInterface is used
  2. Spring Environment should be refreshed with the new values and re-injected as well to beans.

我想要刷新我的上下文,但这会产生问题。
我想可能会使用setter进行注入,并在重新配置属性后重新使用这些setter。是否有这种要求的工作实践?

I thought of refreshing my context but that creates problems. I thought maybe to use setters for injection and re-use those setters once properties are re-configured. Is there a working practice for such a requirement?

任何想法?

更新

正如一些人所建议我可以使用包含两种实现(ImplA和ImplB)的工厂/注册表,并通过查询相关属性返回正确的实现。
如果我这样做,我还有第二个挑战 - 环境。例如,如果我的注册表看起来像这样:

As some suggested I can use a factory/registry that holds both implementations (ImplA and ImplB) and returns the right one by querying the relevant property. If I do that I still have the second challenge - the environment. for example if my registry looks like this:

@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;
        }
}
}

一旦房产发生变化,我应该重新注入我的环境。对此提出了什么建议?

Once property has changed I should re-inject my environment. any suggestions for that?

我知道我可以在方法中查询env而不是构造函数但是这是性能降低而且我想想一个ider for重新注入环境(再次,可能使用setter注入?)。

I know I can query that env inside the method instead of constructor but this is a performance reduction and also I would like to think of an ider for re-injecting environment (again, maybe using a setter injection?).

推荐答案

我会尽可能简化此任务。而不是在启动时有条件地加载 MyInterface 接口的一个实现,然后触发一个触发动态加载同一接口的另一个实现的事件,我将解决这个问题的不同这样,实现和维护起来要简单得多。

I would keep this task as simple as possible. Instead of conditionally load one implementation of the MyInterface interface at startup and then fire an event that triggers dynamic loading of another implementation of the same interface, I would tackle this problem in a different way, that is much simpler to implement and maintain.

首先,我只是加载所有可能的实现:

First of all, I'd just load all possible implementations:

@Component
public class MyInterfaceImplementationsHolder {

    @Autowired
    private Map<String, MyInterface> implementations;

    public MyInterface get(String impl) {
        return this.implementations.get(impl);
    }
}

这个bean只是所有实现的持有者 MyInterface 界面。这里没什么了不起的,只是常见的Spring自动装配行为。

This bean is just a holder for all implementations of the MyInterface interface. Nothing magic here, just common Spring autowiring behavior.

现在,无论你需要注入 MyInterface的特定实现 ,您可以在界面的帮助下完成:

Now, wherever you need to inject a specific implementation of MyInterface, you could do it with the help of an interface:

public interface MyInterfaceReloader {

    void changeImplementation(MyInterface impl);
}

然后,对于需要通知的每个班级更改实现,只需使其实现 MyInterfaceReloader 接口。例如:

Then, for every class that needs to be notified of a change of the implementation, just make it implement the MyInterfaceReloader interface. For instance:

@Component
public class SomeBean implements MyInterfaceReloader {

    // Do not autowire
    private MyInterface myInterface;

    @Override
    public void changeImplementation(MyInterface impl) {
        this.myInterface = impl;
    }
}

最后,你需要一个实际改变实现的bean在每个具有 MyInterface 作为属性的bean中:

Finally, you need a bean that actually changes the implementation in every bean that has MyInterface as an attribute:

@Component
public class MyInterfaceImplementationUpdater {

    @Autowired
    private Map<String, MyInterfaceReloader> reloaders;

    @Autowired
    private MyInterfaceImplementationsHolder holder;

    public void updateImplementations(String implBeanName) {
        this.reloaders.forEach((k, v) -> 
            v.changeImplementation(this.holder.get(implBeanName)));
    }
}

这只是自动装配所有实现<$ c的bean $ c> MyInterfaceReloader 接口并使用新实现更新每个实现,该实现从持有者检索并作为参数传递。同样,常见的Spring自动装配规则。

This simply autowires all beans that implement the MyInterfaceReloader interface and updates each one of them with the new implementation, which is retrieved from the holder and passed as an argument. Again, common Spring autowiring rules.

每当你想要改变实现时,你应该只调用 updateImplementations 带有新实现的bean名称的方法,该类是较低的驼峰案例类的简单名称,即 myImplA myImplB 用于类 MyImplA MyImplB

Whenever you want the implementation to be changed, you should just invoke the updateImplementations method with the name of the bean of the new implementation, which is the lower camel case simple name of the class, i.e. myImplA or myImplB for classes MyImplA and MyImplB.

您还应该在启动时调用此方法,以便在实现 MyInterfaceReloader 接口的每个bean上设置初始实现。

You should also invoke this method at startup, so that an initial implementation is set on every bean that implements the MyInterfaceReloader interface.

这篇关于动态注入spring bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆