【发布时间】:2017-10-15 11:43:55
【问题描述】:
作为一名 Java 开发人员,我经常需要在我的接口的不同实现之间进行选择。有时这种选择可以一次完成,而有时我需要不同的实现来响应我的程序接收到的不同输入。换句话说,我需要能够在运行时更改 实现。这很容易通过一个帮助对象来实现,该对象将一些键(基于用户输入)转换为对合适接口实现的引用。
使用 Spring,我可以将这样的对象设计为 bean,并将其注入到我需要的任何地方:
public class MyClass {
@Autowired
private MyHelper helper;
public void someMethod(String someKey) {
AnInterface i = helper.giveMeTheRightImplementation(someKey);
i.doYourjob();
}
}
现在,我应该如何实现帮助程序?让我们从这个开始:
@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 类:
@Service
public class Foo {
@Autowired
private VeryCoolService coolService;
...
}
...MyHelper 返回的 Foo 实例不会正确初始化 coolService 字段。
为避免这种情况,经常建议的解决方法是在帮助器中注入每个可能的实现:
@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 ...
}
}
但我不喜欢这种解决方案。我发现像这样更优雅和可维护的东西:
@Service
public class MyHelper {
@Autowired
private ApplicationContext app;
public AnInterface giveMeTheRightImplementation(String key) {
return (AnInterface) app.getBean(key);
}
}
这是基于 Spring 的ApplicationContext。
类似的解决方案是使用ServiceLocatorFactoryBean 类:
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 专家,我想知道是否有更好的方法。
【问题讨论】:
-
你可以在你的方法中传递一个类而不是一个字符串,比如
Foo.class。 -
@Nathan 我不确定你的提议。请注意,选择正确的课程是问题,而不是解决方案。
-
一定要按键查找吗?如果您的解决方案只是解决该问题以区分同一接口的实现,那么使用
@Qualifier自动装配并按名称引用 bean 可能会对您有所帮助。 -
@msparer 目标是能够将某种输入转化为合适的实现。在我的示例中,我使用了一个名为
someKey的字符串,它被视为 bean 名称,但不一定是这种情况。它甚至可以是一个数字,并且可以根据这个数字的大小来选择实现,其中一些实现对小数字更有效,而另一些对更大的数字更有效。此外,@Qualifier也无济于事,因为它可以让您选择特定的 bean,但是一旦连接好,您就无法切换到另一个 :-/ -
看来问题和this类似
标签: java spring dependency-injection interface polymorphism