基于传递给方法的参数,我需要从许多Spring bean中选择一个,这些Spring bean是同一个类的实现,但配置了不同的参数。
E.g。如果用户A调用该方法,我需要在bean A上调用dooFoo()
,但如果它是用户B,那么我需要调用相同的方法,仅在bean B上调用。
除了将所有bean都粘贴在地图中,并从传递给我方法的参数中获取一个键之外,还有一种“更加弹性”的方法吗?
答案 0 :(得分:10)
我们在项目中遇到了这个问题,我们通过Factory-Like类来解决它。客户端类 - 在运行时需要bean的客户端类 - 有一个工厂实例,它是通过Spring注入的:
@Component
public class ImTheClient{
@Autowired
private ImTheFactory factory;
public void doSomething(
Parameters parameters) throws Exception{
IWantThis theInstance = factory.getInstance(parameters);
}
}
因此,IWantThis
实例取决于parameters
参数的运行时值。 Factory实现如下:
@Component
public class ImTheFactoryImpl implements
ImTheFactory {
@Autowired
private IWantThisBadly anInstance;
@Autowired
private IAlsoWantThis anotherInstance;
@Override
public IWantThis getInstance(Parameters parameters) {
if (parameters.equals(Parameters.THIS)) {
return anInstance;
}
if (parameters.equals(Parameters.THAT)) {
return anotherInstance;
}
return null;
}
}
因此,工厂实例保留对IWantThis
类的两个有效值的引用,IWantThisBadly
和IAlsoWantThis
两个IWantThis
的实现。
答案 1 :(得分:2)
将它们粘贴在地图中听起来不错。如果它是一个Spring管理的地图(使用util:map
,或者在Java配置中),那比在其他地方创建它更好,因为Spring拥有所有对象引用并且可以正确地管理它们的生命周期。
答案 2 :(得分:2)
好像你想要一个ServiceLocator
使用应用程序上下文作为注册表。
请参阅ServiceLocatorFactoryBean支持类,创建ServiceLocators,将键映射到bean名称,而不将客户端代码耦合到Spring。
其他选项是使用命名约定或基于注释的配置。
例如,假设您使用@ExampleAnnotation("someId")
注释服务,您可以使用类似以下服务定位器的内容来检索它们。
public class AnnotationServiceLocator implements ServiceLocator {
@Autowired
private ApplicationContext context;
private Map<String, Service> services;
public Service getService(String id) {
checkServices();
return services.get(id);
}
private void checkServices() {
if (services == null) {
services = new HashMap<String, Service>();
Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class);
for (Object bean : beans.values()) {
ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class);
services.put(ann.value(), (Service) bean);
}
}
}
}
答案 3 :(得分:-1)
如果您正在谈论的bean(A,B)是SessionScope
,那么它们就没有问题,它们将被正确选择。
public class BusinessLogic {
private BaseClassOfBeanAandB bean;
public void methodCalledByUserAorB() {
bean.doFoo();
}
}