我正在JavaSE应用程序中使用Weld for Cdi。
我的某些服务有两种风格。通过Qualifier
(@Italian
或@Chinese
)在CDI中的区别。
大多数服务代码位于共享的超类中。
该超类使用其他服务。那些具有通用实现的对象只需注入超类(TimerService
)中。
但是,如果有特定的实现,则取决于要选择哪种实现的子类。
在下面的示例中:ItalianFoodController
调用service.cookSoup()
时,应使用意大利食谱作为汤料...
public abstract class FoodService {
@Inject TimerService timerService;
abstract protected RecipeService getRecipeService();
protected void cookSoup() {
getRecipeService().getSoupRecipe();
timerService.setTimer(20);
...
}
}
@ApplicationScoped @Italian
public class ItalianFoodService extends FoodService {
@Inject @Italian RecipeService recipeService;
@Override
protected RecipeService getRecipeService() {
return recipeService;
}
...
}
@ApplicationScoped @Chinese
public class ChineseFoodService extends FoodService {
@Inject @Chinese RecipeService recipeService;
...
}
public class ItalianFoodController {
@Inject @Italian ItalianFoodService service;
...
public void cook() {
service.cookSoup();
}
}
该示例运行正常。
我的问题是:是否有CDI模式可以摆脱getRecipeService()
?
最直观的方法是:
public abstract class FoodService {
@Inject RecipeService recipeService;
...
}
public class ItalianFoodService extends FoodService {
@Inject @Italian RecipeService recipeService;
...
}
但是这不起作用,因为配方服务将被隐藏,但不会被子类覆盖。
答案 0 :(得分:0)
是的,有一个,叫做Instance.select(qualifier)
。这就是它的工作方式:
public abstract class FoodService {
@Inject
TimerService timerService;
@Any
@Inject
Instance<RecipeService> recipeServices;
private final Annotation recipeSelector;
FoodService(){
//this is just one way you can get hold of the qualifier for each soup service
// another way is to look into AnnotationLiteral
recipeSelector = Arrays.stream(getClass().getDeclaredAnnotations())
.filter((ann) -> annot.annotationType().isAnnotationPresent(Qualfiier.class))
.findFirst()
.orElseThrow(()-> new someexception());
}
protected void cookSoup() {
RecipeService service = recipeServices.select(recipeSelector).get().getSoupRecipe();
timerService.setTimer(20);
}
}
有关此的更多详细信息: http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#dynamic_lookup 和 http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#annotationliteral_typeliteral
答案 1 :(得分:0)
考虑@maress的答案,我想出了另一种方法,使我可以非常直观地使用注入的服务。
使用构造函数注入的解决方案:
public abstract class FoodService {
protected RecipeService recipeService;
FoodService (RecipeService recipeService) {
this.recipeService = recipeService;
}
}
public class ItalianFoodService extends FoodService {
// Only needed if ItalianRecipeService holds additional methods.
@Inject @Italian ItalianRecipeService recipeService;
@Inject
ItalianFoodService(@Italian RecipeService recipeService) {
super(recipeService);
}
}
同样可以通过
使用@PostConstruct的解决方案:
public abstract class FoodService {
protected RecipeService recipeService;
}
public class ItalianFoodService extends FoodService {
// Only needed if ItalianRecipeService holds additional methods.
@Inject @Italian ItalianRecipeService recipeService;
@PostConstruct
postConstruct() {
super.recipeService = recipeService;
}
}
这两种解决方案都非常简短易读,而使用构造函数注入的解决方案则对注入更为明确。