gpt4 book ai didi

jsf - 如何在多个类实现中使用 CDI 限定符?

转载 作者:行者123 更新时间:2023-12-02 01:13:49 28 4
gpt4 key购买 nike

我是 Java EE/JSF 的新手,现在阅读 CDI 限定符 - 更改类实现的可能性。这很好,但我有一个问题。据我了解,我可以使用限定符更改类实现,但我需要在使用此实现的任何地方更改它。在一个地方进行此操作的最佳解决方案是什么?凭借我对 Java EE 的一点了解,我发现了这一点。

假设我们正在创建简单的计算器应用程序。我们需要创建几个类:

  • Calculator (计算器的基本实现)
  • ScientificCalculator (计算器的科学实现)
  • MiniCalculator (潜力最小)
  • MockCalculator (用于单元测试)
  • 预选赛 @Calculator (将指示计算器的实际实现;我应该为每个实现创建限定符吗?)

  • 这是问题。我有四种计算器实现,我想在少数地方使用其中一种,但每次只使用一种(在最初的项目阶段,我将使用 MiniCalculator,然后是 Calculator 等等)。如何在注入(inject)对象的每个地方更改实现而不更改代码?我是否应该创建工厂来负责注入(inject)并作为 method injector 工作? ?我的解决方案正确且有意义吗?

    工厂
    @ApplicationScoped
    public class CalculatorFctory implements Serializable {
    private Calculator calc;

    @Produces @Calculator Calculator getCalculator() {
    return new Calculator();
    }
    }

    使用计算器的类(class)
    public class CalculateUserAge {
    @Calculator
    @Inject
    private Calculator calc;
    }

    这是正确的解决方案吗?如果我错了或者有更好的解决方案,请纠正我。谢谢!。

    最佳答案

    这里有几个问题。

  • 在整个应用程序中更改所需实现的最佳方法是什么?查看 @Alternatives .
  • 每个实现都需要一个限定符吗?不,见 this回答冗长而详细的解释。
  • 我应该使用生产者来决定注入(inject)哪个实现吗?可能是您想要的解决方案,但我对此表示怀疑。生产者通常用于执行某种无法在构造函数中完成的初始化/@PostConstruct .您还可以使用它来检查注入(inject)点并在运行时决定注入(inject)什么。有关一些线索,请参见链接 2。
  • 这个解决方案正确吗?这会起作用,但是您仍然必须弄乱代码才能更改实现,因此请首先考虑 1.。还有@Calculator Calculator似乎非常多余。同样,请参见 2 处的链接。
    @ApplicationScoped
    public class CalculatorFctory implements Serializable {
    private Calculator calc;

    @Produces @Calculator Calculator getCalculator() {
    return new Calculator();
    }
    }

  • 更新:

    除了类型之外,CDI 还使用限定符来解决依赖关系。换句话说,只要只有一种类型与注入(inject)点的类型匹配,单独的类型就足够了,不需要限定符。当单独的类型还不够时,限定词可以用来消除歧义。

    例如:
    public class ImplOne implements MyInterface {
    ...
    }

    public class ImplTwo implements MyInterface {
    ...
    }

    为了能够注入(inject)任一实现,您不需要任何限定符:
    @Inject ImplOne bean;

    或者
    @Inject ImplTwo bean;

    这就是为什么我说 @Calculator Calculator是多余的。如果您为每个实现定义一个限定符,您不会获得太多,还不如只使用类型。比如说,两个限定符 @QualOne@QualTwo :
    @Inject @QualOne ImplOne bean;


    @Inject @QualTwo ImplTwo bean;

    上面的例子没有任何收获,因为在前面的例子中已经不存在消除歧义了。

    当然,您可以在无法访问特定实现类型的情况下执行此操作:
    @Inject @QualOne MyInterface bean; // to inject TypeOne


    @Inject @QualTwo MyInterface bean; // to inject TypeTwo

    However OP shouldn't be using @Produces when he wants Calculator implementations to be CDI managed.



    @Avinash Singh - CDI 管理 @Produces以及它们返回的任何内容,只要调用该方法的是 CDI。见 this section of the spec如果你能够。这包括返回 `@...Scoped bean,它将支持依赖注入(inject)、生命周期回调等。

    我在这里忽略了一些细节,所以考虑以下两个:
    public class SomeProducer {

    @Inject ImplOne implOne;
    @Inject ImplTwo implTwo;
    @Inject ImplThree implThree;

    @Produces
    public MyInterface get() {
    if (conditionOne()) {
    return implOne;
    } else if (conditionTwo()) {
    return implTwo;
    } else {
    return implThree;
    }
    }
    }


    public class SomeProducer {

    @Produces
    public MyInterface get() {
    if (conditionOne()) {
    return new ImplOne();
    } else if (conditionTwo()) {
    return new ImplTwo();
    } else {
    return new ImplThree;
    }
    }
    }

    然后,在第一个示例中,CDI 将管理从生产者返回的内容的生命周期(即 @PostConstruct@Inject 支持),但在第二个示例中它不会。

    回到最初的问题 - 在无需修改源代码的情况下切换实现的最佳方式是什么?假设您希望更改适用于整个应用程序。
    @Default
    public class ImplOne implements MyInterface {
    ...
    }

    @Alternative
    public class ImplTwo implements MyInterface {
    ...
    }

    @Alternative
    public class ImplThree implements MyInterface {
    ...
    }

    然后,任意 @Inject MyInterface instance , ImplOne将被注入(inject),除非
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <alternatives>
    <class>ImplTwo</class>
    </alternatives>
    </beans>

    指定,在这种情况下 ImplTwo将被注入(inject)各处。

    进一步更新

    Java EE 环境中确实有一些东西不是由 CDI 管理的,例如 EJB 和 Web 服务。

    如何将 Web 服务注入(inject) CDI 托管 bean?真的很简单:
    @WebServiceRef(lookup="java:app/service/PaymentService")
    PaymentService paymentService;

    就是这样,您将获得对在 CDI 外部管理的支付服务的有效引用。

    但是,如果您不想使用完整的 @WebServiceRef(lookup="java:app/service/PaymentService") 怎么办?你需要它的任何地方?如果你只想按类型注入(inject)呢?然后你在某个地方这样做:
    @Produces @WebServiceRef(lookup="java:app/service/PaymentService")
    PaymentService paymentService;

    在任何需要引用该支付服务的 CDI bean 中,您可以简单地 @Inject它像这样使用CDI:
    @Inject PaymentService paymentService;

    请注意,在定义生产者字段之前, PaymentService不能以 CDI 方式注入(inject)。但它总是以旧方式可用。此外,在任何一种情况下,Web 服务都不由 CDI 管理,但定义生产者字段只是使该 Web 服务引用可用于以 CDI 方式注入(inject)。

    关于jsf - 如何在多个类实现中使用 CDI 限定符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15451422/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com