我正在使用Spring DI来连接我的组件,我遇到了这个问题。
我有一个BaseService类,它有多个实现。它上面的层有一个构建器,它调用服务来获取数据来填充POJO。我需要调用的服务实现(ServiceA,ServiceB)根据我需要构建的POJO类型进行更改。
在这种情况下,我如何自动装配服务,因为它需要延迟绑定服务。我该如何处理这种情况? (Spring DI中的示例确实会有帮助)
我读过类似的问题,却找不到答案。我读到服务主机等SOA模式为确切的用例提供了不同的解决方案。
请帮忙。 感谢
答案 0 :(得分:7)
如何使用FactoryBean
:
public class BuilderFactory implements FactoryBean<Builder> {
@Autowired
private ApplicationContext appContext;
...
@Override
public Builder getObject() {
Builder builder = new Builder();
switch(something()) {
case "foo":
builder.service = new ServiceA();
break;
case "bar":
builder.service= new ServiceB();
break;
...
default:
//handle cases where it's unclear which type to create
}
return builder;
}
}
其中Builder
个实例有一个公共/包私有字段BaseService service
,可以在getData()
,buildPojos()
以及其他方法中调用。
(如果您希望此字段为私有,您也可以使用静态工厂方法来实例化Builder
)
答案 1 :(得分:5)
您可以使用ServiceLocatorFactoryBean。在你的情况下,你会做这样的事情:
public interface BaseServiceLocator {
BaseService lookup(String qualifier); //use whatever qualifier type makes sense here
}
<bean id="serviceLocatorFactoryBean"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface"
value="your.package.BaseServiceLocator" />
</bean>
然后你的建造者看起来像这样:
public class Builder {
@Autowired
private BaseServiceLocator baseServiceLocator;
@Override
public YourReturnType businessMethod() {
SomeData data = getData();
BaseService baseService = baseServiceLocator(data.getType()); //here I am assuming that getType() is a String
//whatever
}
答案 2 :(得分:2)
我的一个项目中有相同的要求。我根据pojo要求使用反射来获取服务。这样就没有静态值,即使你将来定义新的pojo和服务,你也不必改变任何实现。
我已经将我的pojos和服务命名为类似。即
POJO名称:Pond5DownloadStrategy
和ServiceName:Pond5DownloadStrategyService
。
我在春天定义了所有服务。我有一个DownloadStrategyFactory有一个方法
getService(Object obj)
。它也被实例化为spring bean。
getService方法做了什么。
我使用obj.getClass().getSimpleName()
将POJO名称作为字符串,然后在最后添加Service。恩。
如果我通过Pond5DownloadStrategy
,那么我执行AppContext.getBean(“Pond5DownloadStrategyService”);
答案 3 :(得分:2)
请查看我的回答here。
虽然是在春季批量主题下,但它实际上与您的问题和策略设计模式有关。
策略A策略B是您的ServiceA,ServiceB等 您需要在Builder类中使用StrategyLocator(在原始答案中,它等效于MyTaskelt)。查找将基于您的pojo类型。
strategy = strategyLocator.lookup(POJOs.class);
在答案中,我建议使用PlugableStrategyMapper,但是如果你预定义所有Servcies,你可以将它们放在application-context.xml中的Map中
答案 4 :(得分:1)
例如,对于手动绑定:
public class Builder {
@Autowired
private Map<String, Service> services;
// Bind pojo classes to bean names.
private Map<Class<?>, String> binding;
public Service getService(Object object) {
return services.get(binding.get(object.getClass()));
}
public Map<Class<?>, String> getBinding() {
return binding;
}
public void setBinding(Map<Class<?>, String> binding) {
this.binding = binding;
}
}
然而,手动绑定可能是重复的,所以如果你真的不需要他的灵活性,你可以使用命名约定(@AmitChotaliya回答)或通过服务方法强制执行绑定。
public interface Service {
Class<?> getTargetType();
}
public class Builder {
@Autowired
private Set<Service> services;
// Bind pojo classes to Services.
private Map<Class<?>, Service> binding = new ConcurrentHashMap<Class<?>, Service>();
@PostConstruct
public void init() {
for (Service service : services) {
binding.put(service.getTargetType(), service);
}
}
public Service getService(Object object) {
return binding.get(object.getClass());
}
}