草庐IT

java - 通过 CDI 动态注入(inject)实例

coder 2024-03-12 原文

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

我需要一些更动态的注入(inject)东西模型。

介绍一下我的问题: 假设我们有接口(interface) Animal 和实现该接口(interface)的三个类:Ant、Dog、Elephant。 我想动态注入(inject)这三个类之一的实例,它取决于一些变量,如字符串(动物名称)。 在 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 接口(interface)的类中,我需要使用带有@EJB 注释的变量。

在 Java EE 中最好和最合适的方法是什么?

编辑:
好的,基于 Svetlin Zarev 和 hwellmann 的回复(谢谢!)我创建了这个:

一开始我们将创建动物模型:

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

}

我不知道把 map animalMap放在那个地方是对的...?

最佳答案

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

您需要一个带有绑定(bind)参数的限定符,例如@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 "";
}

关于java - 通过 CDI 动态注入(inject)实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33583032/

有关java - 通过 CDI 动态注入(inject)实例的更多相关文章

  1. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  2. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  5. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  6. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  7. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  8. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  9. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  10. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

随机推荐