max*_*yme 18 service spring dependency-injection autowired
在给定运行时值的情况下,我找不到一种简单的方法来注入组件/服务.
我开始阅读@ Spring的文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers 但我找不到如何变量传递给@Qualifier注释的值.
假设我有一个具有这种界面的模型实体:
public interface Case {
String getCountryCode();
void setCountryCode(String countryCode);
}
Run Code Online (Sandbox Code Playgroud)
在我的客户端代码中,我会做类似的事情:
@Inject
DoService does;
(...)
Case myCase = new CaseImpl(); // ...or whatever
myCase.setCountryCode("uk");
does.whateverWith(myCase);
Run Code Online (Sandbox Code Playgroud)
......我的服务是:
@Service
public class DoService {
@Inject
// FIXME what kind of #$@& symbol can I use here?
// Seems like SpEL is sadly invalid here :(
@Qualifier("${caze.countryCode}")
private CaseService caseService;
public void whateverWith(Case caze) {
caseService.modify(caze);
}
}
Run Code Online (Sandbox Code Playgroud)
我希望caseService是UKCaseService(参见下面的相关代码).
public interface CaseService {
void modify(Case caze);
}
@Service
@Qualifier("uk")
public class UKCaseService implements CaseService {
}
@Service
@Qualifier("us")
public class USCaseService implements CaseService {
}
Run Code Online (Sandbox Code Playgroud)
那么如何通过使用/所有Spring特性以最简单/优雅/有效的方式"修复"所有这些,所以基本上没有.properties,NO XML,只有注释.但是我已经怀疑我的DoService出了什么问题,因为在注入caseService之前Spring需要知道"case"...但是如果没有客户端代码知道caseService,如何实现这个呢?我无法弄明白......
我已经在SO上阅读了几个问题,但是大多数时候要么他们没有和我一样的需求和/或配置相同,要么发布的答案对我来说不够令人满意(看起来他们基本上都是(旧)Spring功能的变通方法或(旧)用法.
当找到多个匹配的bean时,Spring如何按名称自动装配? =>仅指类似组件的类
动态定义哪个bean在Spring中自动装配(使用限定符) =>真的很有趣,但最详细的答案(4票)是......差不多3年半了?!(2013年7月)
Spring 3 - 动态自动装配在运行时基于另一个对象属性 =>这里非常相似的问题,但答案真的看起来像一个变通方法而不是真正的设计模式(如工厂)?我不喜欢将所有代码实现到ServiceImpl中,因为它已经完成了...
Spring @Autowiring,如何使用对象工厂来选择实现? =>第二个答案看起来很有趣,但它的作者没有扩展,所以尽管我知道(有点)关于Java Config和东西,我不太确定他在谈论什么......
如何在运行时基于具有Spring的属性注入不同的服务而不使用XML =>有趣的讨论,尤其是 答案,但用户有属性设置,我没有.
另请阅读:http: //docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-bean-references =>我找不到关于使用的扩展示例表达式中的"@".有人知道吗?
编辑:找到其他相关的相似问题,没有人得到一个正确的答案: 如何使用@Autowired动态注入实现,如工厂模式 Spring限定符和属性占位符 Spring:将@Qualifier与Property Placeholder一起使用 如何进行条件自动春天接线? @Qualifier 中Spring SpEL中的 动态注入引用相同的bean 如何使用SpEL在Spring中注入方法调用的结果?
工厂模式可能是一个解决方案? 如何使用@Autowired动态注入工厂模式之类的实现
aux*_*aux 17
您可以使用BeanFactory通过名称动态获取上下文中的bean :
@Service
public class Doer {
@Autowired BeanFactory beans;
public void doSomething(Case case){
CaseService service = beans.getBean(case.getCountryCode(), CaseService.class)
service.doSomething(case);
}
}
Run Code Online (Sandbox Code Playgroud)
旁注.使用国家代码之类的东西作为bean名称看起来有点奇怪.添加至少一些前缀或更好地考虑其他一些设计模式.
如果您仍然希望每个国家都有豆,我建议采用另一种方法.引入注册服务以按国家/地区代码获取所需服务:
@Service
public class CaseServices {
private final Map<String, CaseService> servicesByCountryCode = new HashMap<>();
@Autowired
public CaseServices(List<CaseService> services){
for (CaseService service: services){
register(service.getCountryCode(), service);
}
}
public void register(String countryCode, CaseService service) {
this.servicesByCountryCode.put(countryCode, service);
}
public CaseService getCaseService(String countryCode){
return this.servicesByCountryCode.get(countryCode);
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
@Service
public class DoService {
@Autowired CaseServices caseServices;
public void doSomethingWith(Case case){
CaseService service = caseServices.getCaseService(case.getCountryCode());
service.modify(case);
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您必须String getCountryCode()
向您的CaseService
界面添加方法.
public interface CaseService {
void modify(Case case);
String getCountryCode();
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以添加方法CaseService.supports(Case case)
来选择服务.或者,如果您无法扩展界面,则可以CaseServices.register(String, CaseService)
从某个初始化程序或@Configuration
类调用方法.
更新:忘了提一下,Spring已经提供了一个很好的插件抽象来重用样板代码来创建PluginRegistry
这样的东西.
例:
public interface CaseService extends Plugin<String>{
void doSomething(Case case);
}
@Service
@Priority(0)
public class SwissCaseService implements CaseService {
void doSomething(Case case){
// Do something with the Swiss case
}
boolean supports(String countryCode){
return countryCode.equals("CH");
}
}
@Service
@Priority(Ordered.LOWEST_PRECEDENCE)
public class DefaultCaseService implements CaseService {
void doSomething(Case case){
// Do something with the case by-default
}
boolean supports(String countryCode){
return true;
}
}
@Service
public class CaseServices {
private final PluginRegistry<CaseService<?>, String> registry;
@Autowired
public Cases(List<CaseService> services){
this.registry = OrderAwarePluginRegistry.create(services);
}
public CaseService getCaseService(String countryCode){
return registry.getPluginFor(countryCode);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
16322 次 |
最近记录: |