调用 SuperClass 中的服务,其实现注入到子类中
Call a service in SuperClass whose implementation is injected in subclass
我在 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;
...
}
但这不起作用,因为 recipeService 将被隐藏但不会被子类覆盖。
是的,有,叫做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
考虑到@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;
}
}
两种解决方案都非常简短且可读性强,而带有构造函数注入的解决方案对注入的解释更为明确。
我在 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;
...
}
但这不起作用,因为 recipeService 将被隐藏但不会被子类覆盖。
是的,有,叫做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
考虑到@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;
}
}
两种解决方案都非常简短且可读性强,而带有构造函数注入的解决方案对注入的解释更为明确。