【问题标题】:Transitive injection of CDI beanCDI bean的传递注入
【发布时间】:2019-09-27 07:57:30
【问题描述】:

我有一个 REST 控制器

@Path("/greet")
@RequestScoped
public class GreetController {

    @Inject
    private GreeterService greeterService;

    @GET
    @Path("{name}")
    @Produces(TEXT_PLAIN)
    public String greet(@PathParam("name") String name) {
        return greeterService.greet(name);
    }
}

使用 GreeterService

@RequestScoped
public class GreeterService {

    @Inject
    private Greeter greeter;

    public String greet(String name) {
        return greeter.greet(name);
    }
}

GreeterService 本身注入了一个具有两个实现的接口

@RequestScoped
@Hello
public class HelloGreeter implements Greeter {

    @Override
    public String greet(String name) {
        return "Hello " + name;
    }
}

@RequestScoped
@Whazzup
public class WhazzupGreeter implements Greeter {

    @Override
    public String greet(String name) {
        return "Whazzup " + name;
    }
}

@Whazzup@Hello 只是限定符。

我正在尝试根据 GreetController 中使用的限定符将Greeter-Interface 的正确实现注入GreeterService。 这甚至可以使用 CDI 吗? 一个简单的解决方法当然是为每个限定符设置两个 GreeterServices,但这似乎不是一个好主意,因为当添加新的限定符时,GreeterServices 的数量会增加。

当然,这只是一个基本示例,不需要 GreeterServcie,但我不允许将我的公司代码发布到 StackOverflow,因此我必须实现一个简单的示例来重现我们的架构。

提前致谢!

【问题讨论】:

  • 您的描述似乎与您所说的要实现的目标有些矛盾。通过在GreeterController 的注入点上放置一个限定符,您就是说您想要一个具有给定限定符的GreeterService 的实现。例如。对于@Inject @Wazzup GreeterService service,必须有一个GreeterService 类型和限定符@Wazzup 的bean。因此,您使用的限定符越多,您需要的 bean 就越多。
  • 您还可以有一个“终极生产者”,它为给定类型的所有注入点创建 bean,并基于检查注入点来实现。从那里,您可以看到使用了什么限定符。这就是你所追求的吗?不过,它仍然需要您在 @Inject Greeter greeter; 上指定一个限定符。
  • 我想要的是我的GreeterService 根据我在GreetController 中提供的注释选择Greeter 的正确实现。我不知道这是否是实现这种行为的正确方法。
  • GreeterService 类级别的限定注释和控制器中的字段greeterService 只是我尝试的一部分。我在原始帖子中删除了它们。也许这让我的意图更加明确:我想根据控制器控制Greeter的哪个实现将注入GreeterService
  • 我在注入时没有看到合格的注释。谁应该有责任决定应该注入什么 Greeter。那一个应该能够使用限定符。

标签: jakarta-ee dependency-injection cdi


【解决方案1】:

要注入合格的事物,请确保限定词出现在事物和注入点上:

@Inject
@Special
private Thing thing;

@Produces
@Special
private Thing makeSpecialThing() {
    return someSpecialThingCreatedOrGottenFromSomewhere;
}

从您之前的一些 cmets 看来,您似乎已经知道这一点,并且出于任何(可能是有效的,可能不是)原因并不想这样做。

要在运行时动态选择一个东西,即一旦你的应用程序启动,就像你想要做的那样,你可以使用Instance 公开的工具(我特意做了下面的例子 -详细(希望)清晰:

final Instance<Object> instance = ... // get an Instance, e.g. via CDI.current() or BeanManager.createInstance()
final Instance<Thing> anyAndAllThings = instance.select(Thing.class);
final Instance<Thing> onlyTheSpecialThing = anyAndAllThings.select(new AnnotationLiteral<SpecialThing>() {});
final Thing theSpecialThing = onlyTheSpecialThing.get();

此模式可让您随时选择是想要您的Hello-qualified Greeter 还是您的Whazzup-qualified Greeter

通常希望在运行时而不是启动时完成此类工作只是更大问题冰山的一角,但在某些情况下可能是有效的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-02
    • 2015-04-15
    • 2015-02-12
    • 2016-06-08
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多