作为一名Java开发者,我经常需要在不同的接口实现中进行选择。有时,这个选择只需进行一次,而其他时候,根据程序接收到的不同输入,我需要不同的实现。换句话说,我需要能够在运行时更改实现。这可以通过一个辅助对象轻松实现,该对象将某个关键字(基于用户输入)转换为适当的接口实现的引用。
使用Spring,我可以将这样一个对象设计为bean,并在需要的地方注入它:
现在,我应该如何实现这个助手呢?让我们从这里开始:
这样的解决方案有几个缺陷。其中最严重的一个是助手返回的实例对容器来说是未知的,因此无法从依赖注入中受益。换句话说,即使我像这样定义
由于MyHelper返回的Foo实例没有正确初始化coolService字段,为避免这种情况,经常建议的解决方法是在helper中注入每个可能的实现。
但我并不是这样解决方案的铁粉。我觉得更优雅和可维护的是像这样的东西:
这是基于 Spring 的 ApplicationContext。
另一种类似的解决方案是使用 ServiceLocatorFactoryBean 类:
但由于我不是Spring专家,我想知道是否有更好的方法。
使用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字段,为避免这种情况,经常建议的解决方法是在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 ...
}
}
但我并不是这样解决方案的铁粉。我觉得更优雅和可维护的是像这样的东西:
@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
。 - Turtle@Qualifier
进行自动装配并按名称引用bean可能会有所帮助。 - mspsomeKey
的字符串,它被视为 bean 名称,但这并不一定是这样的。它甚至可以是一个数字,并且可以根据该数字的大小选择实现,其中某些实现对小数字更有效,而其他一些实现对大数字更有效。此外,@Qualifier
也没有帮助,因为它允许您选择特定的 bean,但一旦它被连接,您就无法切换到另一个 :-/ - Marco Liceti