【问题标题】:Dynamic CDI Injection at runtime运行时动态 CDI 注入
【发布时间】:2015-06-27 01:23:22
【问题描述】:

这个问题来自我一年前写的my blog post引用。

虽然我为我的 DAO 使用自定义 CDI 限定符,但我想知道是否有一种方法可以动态注入 DAO。

我问的原因如下。现在我有 3 个 CDI 限定符,@HibernateDAO(用于 Hibernate Session 注入类型 DAO)、@JPADAO(用于 JPA 特定的 DAO)和@JDBCDAO(用于纯 JDBCDAO)。这要求我必须在每个具体实现和注入时都指定它。

@Inject @JPADAO
private CustomerDAO customerDAO;

有没有更好的方法可以让我添加各种风格的 DAO,而无需更改代码、编译和部署?

我想在我的项目的下一个版本中引入 MongoDB,我在想我是否可以摆脱 @MongoDBDAO 和注入之类的,

@Inject @MongoDBDAO
private CustomerDAO customerDAO;

我知道 CDI 注入可以允许默认注入和替代注入。我希望其他开发人员可以使用覆盖另一个子类的默认实现,并且能够在不更改现有服务代码的情况下注入它。

这种效果的东西:

@Inject @DAO
private CustomerDAO customerDAO;

@DAO 可以是任何任何风格的 DAO(甚至来自第 3 方),并以某种方式映射 @DAO 以首先找到替代方案,如果未找到,则使用默认实现。

谢谢。

哦!此解决方案必须严格使用最新的(截至撰写本文时)Java EE CDI 规范。使用的技术:

  • RedHat JBoss Wildfly 8.2.0 Final(完全符合 Java EE 7)。
  • Java 8.
  • Java EE 7 API。

我不会对使用 Spring Framework 的解决方案投反对票,因为它可以帮助其他 Spring 开发人员。

【问题讨论】:

标签: java jakarta-ee dependency-injection cdi


【解决方案1】:

如果你想在运行时一般注入 Daos,我会推荐这种方法。

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

  String value();
}

//Dont worry, CDI allows this quite often than not ;)
public class DAOImpl extends AnnotationLiteral<DAO> implements DAO {

   private final String name;
   public DAOImpl(final String name) {
     this.name = name;
   }

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

在需要的地方。

@ApplicationScoped; //Or Whatever
public class MyDAOConsumer {

   @Inject
   @Any
   private Instance<DAOService> daoServices;

   //Just as an example where you can get the dynamic configurations for selecting daos. 
   //Even from property files, or system property.
   @Inject
   private MyDynamicConfigurationService myDanamicConfigurationService;

   public void doSomethingAtRuntime() {
     final String daoToUse = myDanamicConfigurationService.getCurrentConfiguredDaoName();
     final DAO dao = new DAOImpl(daoToUse);

     //Careful here if the DaoService does not exist, you will get UnsatisfiedException
     final DAOService daoService = daoServices.select(dao).get();
     daoService.service();
   }
}

而且,您可以毫不费力地配置在运行时使用哪个 dao。 并且无需更改任何一点点代码。

【讨论】:

  • 第 3 方开发人员如何能够使用这种方法集成他们的服务/DAO?他们将不得不通过在他们的自定义MyDynamicConfigurationService 中添加他们的 DAO 来更改代码并编译。必须有一种更简单的方法,它们不涉及根代码,但具有可以通过 XML 配置或注释注册的自定义代码,并且 CDI 容器知道如何毫无问题地注入它。
  • 我说MyDynamicConfigurationService只是获取动态配置的一种方式。它可能是一个系统变量,可以在系统启动或运行时设置。您如何指定外部配置确实是您的选择,但您的应用程序需要配置,不是吗?
  • DAOServic类是否应该实现DAO接口?
【解决方案2】:

我会忘记自定义注释并使用生产者方法。在该方法中,您可以从 xml 文件或配置文件或任何您想要的方式查找您想要实例化的类。

查看 Java EE 教程中的 Producer Methods

【讨论】:

  • 我想避免自定义配置,因为我必须通过教程和培训将它介绍给 3rd 方开发人员。我想使用现有的 CDI 技术。
  • 使用 new 实例化类时,您不会将 CDI 注入到生产类中。如果你像下面的 maress 建议的那样做,这将起作用。
  • 这就是生产者方法的用途。它们允许您创建 CDI 然后管理的对象。
猜你喜欢
  • 2012-08-05
  • 1970-01-01
  • 2017-07-17
  • 2016-02-08
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2016-10-09
  • 2013-03-05
相关资源
最近更新 更多