调用SuperClass中的服务,该服务的实现被注入子类

时间:2018-07-18 09:25:06

标签: java inheritance cdi weld

我正在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;
    ...    
}

但是这不起作用,因为配方服务将被隐藏,但不会被子类覆盖。

2 个答案:

答案 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_lookuphttp://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;
    }
}

这两种解决方案都非常简短易读,而使用构造函数注入的解决方案则对注入更为明确。