如何使用CDI限定符与多个类实现? [英] How to use CDI qualifiers with multiple class implementations?

查看:129
本文介绍了如何使用CDI限定符与多个类实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Java EE / JSF中是新的,现在阅读有关CDI限定符 - 改变类实现的可能性。这是伟大的,但我有一个问题。据我所知,我可以使用限定符改变类实现,但是我需要使用这个实现来改变它。在一个地方做最好的解决方案是什么?关于Java EE的小知识,我想出了这个。



让我们想象一下,我们正在创建简单的Calculator应用程序。我们需要创建几个课程:


  1. 计算器(计算器的基本实现) / li>
  2. ScientificCalculator (科学实现计算器)

  3. MiniCalculator (最小潜力)

  4. MockCalculator (用于单元测试)

  5. 限定符 @Calculator (将表示计算器的实际实现;我应该为每个实现创建限定词吗?)

这是问题。我有四个计算器的实现,我想在几个地方使用其中一个,但只有一个在时间(在初始项目阶段,我将使用 MiniCalculator ,然后计算器等等)。在每个注入对象的地方,如何更改实现,而无需更改代码?我应该创建将负责注射的工厂,并将作为方法注入器工作?我的解决方案是否正确和有意义?



工厂

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

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

使用计算器的类

  public class CalculateUserAge {
@Calculator
@Inject
私人计算器calc;
}

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

解决方案

如果要使用工厂方法在代码中交换实现,那么您的工厂方法就是管理bean而不是CDI,所以真的不需要 @Calculator

  @ApplicationScoped 
public class CalculatorFactory实现Serializable {
枚举CalculatorType {MiniCaculator,ScientificCaculator,MockCalculator};
计算器getCalculator(CalculatorType calctype){
switch(calctype)
case MiniCaculator:返回新的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(){}
}

然而如果您希望您的Caclulator bean使用@PostConstruct等进行注射和生命周期管理的CDI管理,那么您可以使用以下方法之一。



方法1:



优势:您可以避免使用@Named(miniCaclulator)创建注释



Disadvantage :如果将miniCaclulator从xyzCaclulator发出名称更改,则该方法不会给出错误。

  @Named(miniCaclulator)
class MiniCalculator实现Calculator {...}

@ApplicationScoped
public class CalculatorFactory implements Serializable {
private calc;

@Inject
void setCalculator(@Named(miniCaclulator)Caclulator calc){
this.calc = calc;
}
}

方法2:推荐 (如果任何注射失败,编译器会跟踪注入)

  @Qualifier 
@Retention (RUNTIME)
@Target({FIELD,TYPE,METHOD})
public @interface MiniCalculator {
}

@ApplicationScoped
public class CalculatorFctory implements Serializable {
private calc;

@Inject
void setCalculator(@MiniCalculator calc){
this.calc = calc;
}
}

方法3: em>如果您使用工厂方法来生成对象。它的生命周期不会被管理为CDI,但注入可以使用@Inject工作正常。

  @ApplicationScoped 
public class CalculatorFactory implements Serializable {
private Calculator calc;
@Produces Calculator getCalculator(){
return new Calculator();
}
}
public class CalculateUserAge {
@Inject
private Calculator calc;
}

所有这三种方法都可以用于测试,比如说你有一个名为CaculatorTest的类,

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


I'm new in Java EE/JSF and now read about CDI qualifiers - the possibility to change class implementation. This is great but I have got one question. As far as I understand I can change class implementation using qualifier but I need to change it everywhere I use this implementation. What is the best solution to do it in one place? With my small knowledge about Java EE I figured out this one.

Lets imagine that we are creating simple Calculator application. We need to create few classes:

  1. Calculator (basic implementation of calculator)
  2. ScientificCalculator (scientific implementation of calculator)
  3. MiniCalculator (with minimum potentiality)
  4. MockCalculator (for unit tests)
  5. Qualifier @Calculator (will indicate to the actual implementation of calculator; should I create qualifier for each implementation?)

Here is the question. I've got four implementations of calculator and I want to use one of them in few places but only one at time (in the initial project phase I will use MiniCalculator, then Calculator and so on). How can I change implementation without change code in every place where object is injected? Should I create factory which will be responsible for injecting and will work as method injector? Is my solution correct and meaningful?

Factory

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

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

Class which uses Calculator

public class CalculateUserAge {
    @Calculator
    @Inject
    private Calculator calc;
}

Is this the correct solution? Please correct me if I'm wrong or if there is a better solution. Thanks!.

解决方案

If you want to swap the implementation in your code using a factory method then your factory method is managing the beans and not CDI and so there is really no need for @Calculator.

    @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(){}
}

However if you want your Caclulator beans to be CDI managed for injections and life cycle management using @PostConstruct etc then you can use one of the below approaches.

Approach 1 :

Advantage :You can avoid creating annotation using @Named("miniCaclulator")

Disadvantage : complier will not give an error with this approach if there is a name change from say miniCaclulator to xyzCaclulator.

@Named("miniCaclulator")
class MiniCalculator implements Calculator{ ... }

@ApplicationScoped
public class CalculatorFactory implements Serializable {
    private calc;

    @Inject 
    void setCalculator(@Named("miniCaclulator") Caclulator calc) {
        this.calc = calc;
    }
}

Approach 2 : Recommended (Compiler keeps track of injection if any injection fails)

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface MiniCalculator{
}

@ApplicationScoped
public class CalculatorFctory implements Serializable {
    private calc;

    @Inject 
    void setCalculator(@MiniCalculator calc) {
        this.calc = calc;
    }
}

Approach 3: If you are using a factory method to generate your object.Its lifecycle wont be managed be CDI but the Injection will work fine using @Inject .

@ApplicationScoped
public class CalculatorFactory implements Serializable {
    private Calculator calc;    
    @Produces Calculator getCalculator() {
        return new Calculator();
    }
}    
public class CalculateUserAge {
    @Inject
    private Calculator calc;
}

All three approaches will work for testing , say you have a class named CaculatorTest,

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

if you want to use a mock implementation in your test then do something like this,

   class CalculatorTest{        
        Caclulator calc;        
        @PostConstruct 
                init() {
                    this.calc = createMockCaclulator();
                }
        @Test
        public void testAddition(int a,int b){
          calc.add(a,b);
          .....
        }
        }

这篇关于如何使用CDI限定符与多个类实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆