【问题标题】:Equivalent for @Conditional in CDI等效于 CDI 中的 @Conditional
【发布时间】:2017-09-07 17:41:24
【问题描述】:

我有两个具有后构造初始化的类,我需要基于 vm 参数注入其中一个。我在 spring 中使用 @Conditional 注释完成了这种条件注入,但是我在 CDI 中找不到任何等价物。有人可以帮我解决这个问题吗?

代码是这样的,

public void impl1{
    @PostConstruct
    public void init(){
       ....
    }
    ....
}


public void impl2{
    @PostConstruct
    public void init(){
       ...
    }
    ....
}

如果 vmargument type=1,则必须注入 impl1,如果 type=2,则必须注入 impl2

【问题讨论】:

    标签: java cdi inject


    【解决方案1】:

    可能最好的方法是使用扩展程序。您将创建两个具有相同类型的类,以便它们有资格注入到同一个注入点。然后,使用扩展,您将禁用其中一个,只保留一个有效(另一个不会成为 bean)。

    扩展可以“挂钩”容器生命周期并对其产生影响。您将希望利用 ProcessAnnotatedType<T> 生命周期阶段(第一个阶段之一)告诉 CDI 某个类应该是 @Vetoed。这意味着 CDI 将忽略它并且不会变成 bean。

    注意ProcessAnnotatedType<T> 中的类型参数T - 将其替换为您的实现类型。然后,当 CDI 选择该类时,观察者只会收到一次通知。或者,您可以将 T 替换为两个 impl 共有的某种类型(通常是一个接口),并且观察者将收到两者的通知(然后您需要添加一个登录名以确定通知哪个类)。

    这是一个使用两个观察者的 sn-p。他们每个人只会收到一次通知 - 当 CDI 选择给定的 impl 时 - 如果它与 vm arg 不同,则被否决:

    public class MyExtension implements Extension {
    
      public void observePAT(@Observes ProcessAnnotatedType<Impl1.class> pat){
        // resolve your configuration option, you can alternatively place this login into no-args constructor and re-use
        String vmArgumentType = loadVmArg();
        // if the arg does not equal this impl, we do not want it
        if (! vmArgumentType.equals(Impl1.class.getSimpleName())) {
          pat.veto();
        }
      }
    
      public void observePAT(@Observes ProcessAnnotatedType<Impl2.class> pat){
        // resolve your configuration option, you can alternatively place this login into no-args constructor and re-use
        String vmArgumentType = loadVmArg();
        // if the arg does not equal this impl, we do not want it
        if (! vmArgumentType.equals(Impl2.class.getSimpleName())) {
          pat.veto();
        }
      }
    }
    

    【讨论】:

      【解决方案2】:

      对于运行时决策(更改您的 beans.xml),您基本上有两个选择:

      选项 1:使用生产者方法

      @Produces
      public MyInterface getImplementation() {
         if(runtimeTestPointsTo1)  return new Impl1();
         else                      return new Impl2();
      }
      

      缺点:您使用 new 离开了 bean 创建的世界,因此您的 Impl1 和 Impl2 不能 @Inject 依赖项。 (或者您在生产者 bean 中注入这两种变体并返回其中一个 - 但这意味着两种类型都将被初始化。)

      选项 2:使用 CDI 扩展

      基本上听 processAnotated() 并否决你不想要的一切。优秀的博客入口:http://nightspawn.com/rants/cdi-alternatives-at-runtime/

      【讨论】:

      • 嗨@mtj,不幸的是我需要注入依赖项。将尝试选项 2。
      【解决方案3】:

      创建自己的@Qualifier 并使用它来注入 cdi bean:

      public class YourBean {
      
          @Inject 
          @MyOwnQualifier
          private BeanInterface myEJB;
      }
      
      @Qualifier
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.FIELD, ElementType.METHOD})
      public @interface MyOwnQualifier {
          YourCondition condition();
      }
      

      【讨论】:

      • 嗨@jay smith,谢谢您的快速回复。但是,我没有完全理解您的回答。根据变量“type”的值,我如何确保只注入 imp1 或 impl2 中的一个?我不能同时注入 impl1 和 impl2,因为它们的后构造方法会启动一些过程。我只需要严格启动其中一个。
      • 虽然这说明了 CDI 中一种基本且有用的技术,但不幸的是,答案并未涵盖“运行时”方面。使用限定符注解纯粹是编译时的决定...
      • 这种方法可能不起作用,因为它可能会在某些时候在两个 bean 中调用 init(无法阻止另一个成为 bean 并被使用)。
      猜你喜欢
      • 2017-11-13
      • 2017-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-11-10
      • 1970-01-01
      • 1970-01-01
      • 2023-01-29
      • 2019-01-24
      相关资源
      最近更新 更多