Jsf 如何在多个类实现中使用CDI限定符?
我是JavaEE/JSF新手,现在了解CDI限定符——更改类实现的可能性。这很好,但我有一个问题。据我所知,我可以使用限定符更改类实现,但我需要在使用此实现的任何地方更改它。在一个地方做这件事的最佳解决方案是什么?凭借我对JavaEE的一点了解,我找到了这个 让我们想象一下,我们正在创建一个简单的计算器应用程序。我们需要创建几个类:Jsf 如何在多个类实现中使用CDI限定符?,jsf,jakarta-ee,jsf-2,dependency-injection,cdi,Jsf,Jakarta Ee,Jsf 2,Dependency Injection,Cdi,我是JavaEE/JSF新手,现在了解CDI限定符——更改类实现的可能性。这很好,但我有一个问题。据我所知,我可以使用限定符更改类实现,但我需要在使用此实现的任何地方更改它。在一个地方做这件事的最佳解决方案是什么?凭借我对JavaEE的一点了解,我找到了这个 让我们想象一下,我们正在创建一个简单的计算器应用程序。我们需要创建几个类: 计算器(计算器的基本实现) 科学计算器(计算器的科学实现) 小型计算器(潜力最小) MockCalculator(用于单元测试) 限定符@Calculator(将指
计算器
(计算器的基本实现)科学计算器
(计算器的科学实现)小型计算器
(潜力最小)MockCalculator
(用于单元测试)@Calculator
(将指示计算器的实际实现;我是否应该为每个实现创建限定符?)miniculator
,然后使用calculator
等等)。在注入对象的每个地方,我如何在不更改代码的情况下更改实现?我是否应该创建一个工厂,负责注射并作为方法注入器
?我的解决方案正确且有意义吗
工厂
@ApplicationScoped
public class CalculatorFctory implements Serializable {
private Calculator calc;
@Produces @Calculator Calculator getCalculator() {
return new Calculator();
}
}
使用计算器的类
public class CalculateUserAge {
@Calculator
@Inject
private Calculator calc;
}
这是正确的解决方案吗?如果我错了或者有更好的解决办法,请纠正我。谢谢 这里有几个问题
@PostConstruct
中无法完成的某种初始化。您还可以使用它来检查注入点,并在运行时决定注入什么。参见链接2。寻找一些线索@Calculator
似乎是高度冗余的。同样,请参见第2页的链接
@ApplicationScoped
public class CalculatorFctory implements Serializable {
private Calculator calc;
@Produces @Calculator Calculator getCalculator() {
return new Calculator();
}
}
public class ImplOne implements MyInterface {
...
}
public class ImplTwo implements MyInterface {
...
}
为了能够注入任一实现,您不需要任何限定符:
@Inject ImplOne bean;
或
这就是为什么我说@Calculator
是多余的。如果您为每个实现定义了一个限定符,那么您不会获得太多,最好只使用该类型。比如说,两个限定符@QualOne
和@QualTwo
:
@Inject @QualOne ImplOne bean;
及
上面的例子没有任何好处,因为在前面的例子中,不存在歧义
当然,您可以在无法访问特定实现类型的情况下执行此操作:
@Inject @QualOne MyInterface bean; // to inject TypeOne
及
然而,当OP希望计算器实现由CDI管理时,他不应该使用@products
@Avinash Singh-CDI管理@生成的以及它们返回的任何内容,只要调用该方法的是CDI。请你看看。这包括返回`@…作用域bean,它将支持依赖项注入、生命周期回调等
我忽略了这里的一些细节,所以请考虑下面两个:
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;
}
}
}
及
然后,在第一个示例中,CDI将管理从生产者返回的内容的生命周期(即@PostConstruct
和@Inject
支持),但在第二个示例中不会
回到最初的问题——不必修改源代码就可以在实现之间切换的最佳方式是什么?假设您希望更改是应用程序范围内的
@Default
public class ImplOne implements MyInterface {
...
}
@Alternative
public class ImplTwo implements MyInterface {
...
}
@Alternative
public class ImplThree implements MyInterface {
...
}
然后,对于任何@injectmyinterface实例
,将注入ImplOne
,除非
<?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>
就是这样,您将拥有对CDI外部管理的支付服务的有效引用
但是,如果您不想在任何需要的地方使用完整的@webservicef(lookup=“java:app/service/PaymentService”)
,该怎么办?如果您只想按类型注入它呢?然后你在某个地方这样做:
@Produces @WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
在任何需要对该支付服务进行引用的CDIBean中,您只需使用CDI将其注入,如下所示:
@Inject PaymentService paymentService;
请注意,在定义producer字段之前,PaymentService
将无法通过CDI方式注入。但它总是以旧的方式提供。也,在任何一种情况下,web服务都不是由CDI管理的,但是定义producer字段只是使web服务引用可以通过CDI方式注入。如果您想使用工厂方法交换代码中的实现,那么工厂方法是管理bean而不是CDI,因此实际上不需要@计算器
@ApplicationScoped
public class CalculatorFactory implements Serializable {
enum CalculatorType{MiniCaculator,ScientificCaculator,MockCalculator};
Calculator getCalculator(CalculatorType calctype) {
switch(calctype)
case MiniCaculator : return new MiniCalculator();
case ScientificCalculator : new ScientificCalculator();
case MockCalculator : new MockCalculator();
default:return null;
}
}
public class CalculatorScientificImpl {
private Calculator calc =
CalculatorFactory.getCaclulator(CaclutorType.ScientificCalculator);
doStuff(){}
}
public class CalculatorTest {
private Calculator calc =
CalculatorFactory.getCaclulator(CaclutorType.MockCalculator);
doStuff(){}
}
但是如果您希望使用@PostConstruct等对Caclulator bean进行CDI管理以进行注射和生命周期管理,则可以使用以下方法之一
方法1:
优点:您可以避免使用@Named(“小型计算器”)
缺点:如果名称从sayminiculator
更改为xyzCalculator
,编译器将不会给出这种方法的错误
@Named("miniCalculator")
class MiniCalculator implements Calculator{ ... }
@ApplicationScoped
public class CalculatorFactory implements Serializable {
private calc;
@Inject
void setCalculator(@Named("miniCalculator") Caclulator calc) {
this.calc = calc;
}
}
方法2:推荐
@WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
@Produces @WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
@Inject PaymentService paymentService;
@ApplicationScoped
public class CalculatorFactory implements Serializable {
enum CalculatorType{MiniCaculator,ScientificCaculator,MockCalculator};
Calculator getCalculator(CalculatorType calctype) {
switch(calctype)
case MiniCaculator : return new MiniCalculator();
case ScientificCalculator : new ScientificCalculator();
case MockCalculator : new MockCalculator();
default:return null;
}
}
public class CalculatorScientificImpl {
private Calculator calc =
CalculatorFactory.getCaclulator(CaclutorType.ScientificCalculator);
doStuff(){}
}
public class CalculatorTest {
private Calculator calc =
CalculatorFactory.getCaclulator(CaclutorType.MockCalculator);
doStuff(){}
}
@Named("miniCalculator")
class MiniCalculator implements Calculator{ ... }
@ApplicationScoped
public class CalculatorFactory implements Serializable {
private calc;
@Inject
void setCalculator(@Named("miniCalculator") Caclulator calc) {
this.calc = calc;
}
}
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface MiniCalculator{
}
@ApplicationScoped
public class CalculatorFactory implements Serializable {
private calc;
@Inject
void setCalculator(@MiniCalculator calc) {
this.calc = calc;
}
}
@ApplicationScoped
public class CalculatorFactory implements Serializable {
private Calculator calc;
@Produces Calculator getCalculator() {
return new Calculator();
}
}
public class CalculateUserAge {
@Inject
private Calculator calc;
}
class ScientificCalculatorTest{
Caclulator scientificCalculator;
@Inject
private void setScientificCalculator(@ScientificCalculator calc) {
this.scientificCalculator = calc;
}
@Test
public void testScientificAddition(int a,int b){
scientificCalculator.add(a,b);
....
}
}
class CalculatorTest{
Caclulator calc;
@PostConstruct
init() {
this.calc = createMockCaclulator();
}
@Test
public void testAddition(int a,int b){
calc.add(a,b);
.....
}
}