2015-11-07 56 views
4

在具有CDI的Java EE平台中,可以注入POJO类的实例。 以非常简单的方式,我们需要使用@Inject注释来注入某个Interface的默认实例。我们也可以使用限定符向我们的领域注入具体类。 但这些解决方案相当静态。通过CDI动态注入实例

我需要一些更多的注入动力学模型。

让我来介绍一下我的问题: 假设我们有接口Animal和三个实现该接口的类:Ant,Dog,Elephant。 我想动态注入这三个类中的一个的实例,它取决于一些变量,如字符串(动物名称)。 在Java SE我愿意做它象下面这样:

Map<String, Animal> animalMap = new HashMap<>(); 
animalMap.put("ant", new Ant()); 
animalMap.put("dog", new Dog()); 
animalMap.put("elephant", new Elephant()); 
... 
String animalName = ...; 
Animal animal = animalMap.get(animalMap); 
animal.doSomething(); 

所以,我需要这样的东西:

class AnimalManager { 
    @Inject // ? 
    private Animal animal; // ? 

    public void run(String animalName) { 
     // based on animalName get new instance of animal and run doSomething() 
     ... 
     animal.doSomething(); // if animalName is "ant" call the doSomething on Ant class 
    } 
} 

在实现Animal接口,我需要使用变量与@EJB注释的所有类。

什么是在Java EE中最好也是最正确的方法?

编辑:
基于从Svetlin Zarev和hwellmann响应 OK我创造了这个(感谢!):

在一开始,我们将建立动物模型:

@Qualifier 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.FIELD, ElementType.TYPE}) 
public @interface AnimalModel { 

    Type value(); 

    enum Type { ANT, DOG, ELEPHANT } 

} 

让我们创建的动物:

public interface Animal { 
    public void eat(Object food); 
} 

接下来,具体类:

@AnimalModel(AnimalModel.Type.ANT) 
public class Ant implements Animal { 

    @Override 
    public void eat(Object food) { 
     ... 
    } 

} 

@AnimalModel(AnimalModel.Type.DOG) 
public class Dog implements Animal { 

    @Override 
    public void eat(Object food) { 
     ... 
    } 

} 

@AnimalModel(AnimalModel.Type.ELEPHANT) 
public class Elephant implements Animal { 

    @Override 
    public void eat(Object food) { 
     ... 
    } 

} 

接下来,AnimalLiteral:

public class AnimalLiteral extends AnnotationLiteral<AnimalModel> implements AnimalModel { 

    private static final long serialVersionUID = 1L; 
    private Type type; 
    public AnimalLiteral(Type type) { 
     this.type = type; 
    } 

    public Type value() { 
     return type; 
    } 
} 

主要成分是动物工厂:

@Dependent 
public class AnimalFactory { 

    @Inject 
    @Any 
    private Instance<Animal> animals; 

    private static Map<String, AnimalModel.Type> animalMap; 

    public AnimalFactory() { 
     animalMap = new HashMap<>(); 
     animalMap.put("ant", AnimalModel.Type.ANT); 
     animalMap.put("dog", AnimalModel.Type.DOG); 
     animalMap.put("elephant", AnimalModel.Type.ELEPHANT); 
    } 

    public Animal getAnimal(String animalName) { 
     AnimalModel.Type type = animalMap.get(animalName); 
     AnimalLiteral literal = new AnimalLiteral(type); 
     Instance<Animal> animalInstance = animals.select(literal); 
     return animalInstance.get(); 
    } 
} 

和客户端:

public class Client { 

    @Inject 
    private AnimalFactory animalFactory; 

    public void run(String animalName) { 
     Animal animal = animalFactory.getAnimal(animalName); 
     animal.eat("some food..."); 
    } 

} 

我不知道把地图在那个地方的动物地图是正确的...?

+0

使用构造函数注入而不是场注入。 – chrylis

回答

1

我不认为用CDI实现这种动态注入是可能的,因为当容器实例化托管bean时会注入依赖关系。换句话说,当您在AnimalManager上调用run()时,Animal依赖项已经被注入。

你可以做的是注入AnimalFactory,并在每次通话时只需做出如AnimalFactory.createAnimal(animal);或使用诸如地图方式之类的东西。

+0

这不仅仅是降低我的答案并重申它的含义? – BadZen

+0

你正在谈论HK2,CDI替代品,SOAP,Spring,设计和其他曼波詹博,但你没有解释为什么普通CDI不起作用,也没有提到达到预期目标的具体机制。只需比较我的简短,有意识和清楚的答案,其中包括一(1)句与你的“小说”。 –

+0

这是不正确的。当您尝试使用CDI时,CDI会查找实例。当你刚刚调用'AnimalManager#run'时,可能不存在'Animal'实例。当你调用'animal.doSomething'时 - 这就是'Animal'实例被查找或创建的时间。 'AnimalManager#动物'不是直接引用,它是一个上下文代理。 –

5

结合限定符使用Instance<T>是CDI执行动态注入的标准方法。

您需要带有绑定参数的限定符,例如@Species("ant")来区分你的实现类。

public class AnimalSelector { 

    @Inject 
    @Any 
    private Instance<Animal> animals; 

    public Animal selectAnimalBySpecies(String speciesName) { 
     SpeciesLiteral qualifier = new SpeciesLiteral(speciesName); 
     return animals.select(qualifier).get(); 
    } 
} 

public class SpeciesLiteral extends AnnotationLiteral<Species> implements Species { 

    private String name; 

    public SpeciesLiteral(String name) { 
     this.name = name; 
    } 

    @Override 
    public String value() { 
     return name; 
    } 
} 

@Qualifier 
@Target({ TYPE, METHOD, PARAMETER, FIELD }) 
@Retention(RUNTIME) 
@Documented 
public @interface Species { 

    String value() default ""; 
}