Java 调用超类中的服务,其实现被注入子类

Java 调用超类中的服务,其实现被注入子类,java,inheritance,cdi,weld,Java,Inheritance,Cdi,Weld,我正在JavaSE应用程序中使用Weld for Cdi。 我的一些服务有两种风格。通过限定符区分CDI(意大利语或中文)。 大多数服务代码位于共享超类中 这个超类使用其他服务。那些具有公共实现的只需注入超类(TimerService)。 但是,如果有特定的实现,则取决于要选择的实现的子类。 在下面的示例中:当ItalianFoodController调用service.cookSoup()时,它应该使用意大利菜谱制作汤 public abstract class FoodService {

我正在JavaSE应用程序中使用Weld for Cdi。
我的一些服务有两种风格。通过限定符区分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将被隐藏,但不会被子类覆盖。

是的,有,它被称为
实例。选择(限定符)
。这就是它的工作原理:

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);
    }
}
公共抽象类FoodService{
@注入
TimerService TimerService;
@任何
@注入
实例服务;
私人最终选举人;
餐饮服务{
//这只是您获得每个汤服务的限定符的一种方法
//另一种方法是研究AnnotationLiteral
recipeSelector=Arrays.stream(getClass().getDeclaredAnnotations())
.filter((ann)->annot.annotationType().isAnnotationPresent(Qualfiier.class))
.findFirst()
.orelsetrow(()->newsomeexception());
}
受保护的空煮汤(){
RecipeService service=recipeServices.select(recipeSelector.get().getSoupRecipe();
timerService.setTimer(20);
}
}
详情如下: 和

考虑到@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);
    }
}
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;
    }
}
或者,也可以通过以下方式实现

使用@PostConstruct:的解决方案

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);
    }
}
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;
    }
}

这两种解决方案都非常简短,可读性很强,而使用构造函数注入的解决方案则稍微更详细地解释了注入。

Thx,因为您知道如何在构造函数中处理限定符。这让我找到了一种不同的方法(见下面的答案)。如果需要多个CDI实例,我有时会使用实例。但是在这种情况下,它并不能像我的第一种方法那样帮助我提高代码的可读性。