Spring:如何在运行时更改接口实现 [英] Spring: how to change interface implementations at runtime

查看:89
本文介绍了Spring:如何在运行时更改接口实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为Java开发人员,我经常需要在接口的不同实现之间进行选择。有时这个选择可以一次完成,而有些时候我需要不同的实现来响应我的程序收到的不同输入。换句话说,我需要能够在运行时更改实现。这可以通过一个帮助对象轻松实现,该对象将一些键(基于用户输入)转换为对合适的接口实现的引用。

As a Java developer I frequently need to choose between different implementations of my interfaces. Sometimes this choice can be done once, while some other times I need different implementations in response to the different inputs that my program receives. In other words, I need to be able to change implementation at runtime. This is easily achievable through an helper object that converts some key (based on user input) into a reference to a suitable interface implementation.

使用Spring我可以设计这样的对象作为一个bean并将其注入我需要的地方:

With Spring I can design such an object as a bean and inject it wherever I need:

public class MyClass {

    @Autowired
    private MyHelper helper;

    public void someMethod(String someKey) {
        AnInterface i = helper.giveMeTheRightImplementation(someKey);
        i.doYourjob();
    }

}

现在,我应该如何实施帮手?让我们从这开始:

Now, how should I implement the helper? Let's start with this:

@Service
public class MyHelper {

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return new Foo();
        else if (key.equals("bar")) return new Bar();
        else ...
    }

}

这样的解决方案有几个缺陷。最糟糕的是,从帮助程序返回的实例对于容器是未知的,因此不能从依赖注入中受益。换句话说,即使我像这样定义 Foo 类:

Such a solution has several flaws. One of the worst is the fact that instances returned from the helper are unknown to the container and thus cannot benefit from dependency injection. In other words, even if I define the Foo class like this:

@Service
public class Foo {

    @Autowired
    private VeryCoolService coolService;

    ...

}

。由 MyHelper 返回的 Foo 的实例将没有 coolService 字段已正确初始化。

...instances of Foo returned by MyHelper won't have the coolService field properly initialized.

为避免这种情况,经常建议的解决方法是在帮助程序中注入每个可能的实现

To avoid this, a frequently suggested workaround is to inject each possible implementation inside the helper:

@Service
public class MyHelper {

    @Autowired
    private Foo foo;

    @Autowired
    private Bar bar;

    ...

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return foo;
        else if (key.equals("bar")) return bar;
        else ...
    }

}

但我不是这种解决方案的忠实粉丝。我找到了更优雅和可维护的东西:

But I'm not a big fan of such solutions. I find more elegant and maintainable something like this:

@Service
public class MyHelper {

    @Autowired
    private ApplicationContext app;

    public AnInterface giveMeTheRightImplementation(String key) {
        return (AnInterface) app.getBean(key);
    }

}

这是基于Spring的 ApplicationContext

This is based on Spring's ApplicationContext.

类似的解决方案是使用 ServiceLocatorFactoryBean 类:

A similar solution is to use the ServiceLocatorFactoryBean class:

public interface MyHelper {

    AnInterface giveMeTheRightImplementation(String key);

}

// Somewhere else, in Java config

@Bean
ServiceLocatorFactoryBean myHelper() {
    ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
    bean.setServiceLocatorInterface(MyHelper.class);
    return bean;
}

但由于我不是Spring专家,我想知道是否有更好的方法。

But since I'm not a Spring expert I wonder if there are even better approaches.

推荐答案

做你想做的事的标准方法应该是:

The standard way of doing what you want should be this:

interface YourInterface {
    void doSomething();
}

public class YourClass {

    @Inject @Any Instance<YourInterface> anImplementation;

    public void yourMethod(String someInput) {
        Annotation qualifier = turnInputIntoQualifier(someInput);
        anImplementation.select(qualifier).get().doSomething();
    }

    private Annotation turnInputIntoQualifier(String input) {
        ...
    }

}

目前,
Spring不支持它(尽管
计划用于v5.x)。它应该工作在
应用程序服务器

如果你想坚持使用Spring,那么基于 ServiceLocatorFactoryBean 的解决方案
可能是最好的。

If you want to stick with Spring, the ServiceLocatorFactoryBean based solution is probably the best one.

这篇关于Spring:如何在运行时更改接口实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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