通过大量XML配置外部资源

发布者:    |       CDI

假设我们有一个外部资源,比如数据库,我们希望它能根据部署环境进行更改。在CDI中,我们使用生产者字段声明来声明资源。

class CustomerDatabase {
   static 
   @Resource(lookup="java:global/env/jdbc/CustomerDatasource")
   @Produces @CustomerDatabase
   Datasource customerDatabase;
}

该字段声明的目的是关联数据源和绑定类型@CustomerDatabase与具有全局JNDI名称的Java EE资源java:global/env/jdbc/CustomerDatasource.

现在我们可以轻松地将我们的数据源注入到任何需要它的bean中

public class Bean {
   private Datasource customerDatabase;

   @Inject public Bean(@CustomerDatabase Datasource ds) {
       customerDatabase = ds;
   }
   ...
}

现在,这个注入的资源引用已经非常可配置了。JNDI名称只是一个逻辑名称。实际指向的数据源可以很容易地根据部署进行更改。我们当然没有硬编码JDBC URL、用户名和密码!但是,让我们假设这还不够。CDI允许你定义bean的替代实现。

class TestCustomerDatabase {
   static 
   @Resource(lookup="java:global/env/jdbc/TestDatasource") 
   @Produces @Alternative @CustomerDatabase 
   Datasource testCustomerDatabase;
}
@Alternative @CustomerDatabase
class MockCustomerDatabase implements Datasource {
   //operations of Datasource go here!
   ...
}

这两个类都提供了@CustomerDatabase 数据源的替代实现。默认情况下,CDI会忽略这些bean,并继续使用原始实现,因为它是唯一没有声明的实现@Alternative.

然而,如果我们声明其中一个替代方案在beans.xml中,CDI将使用该实现

<beans>
   <alternatives>
      <class>org.mycompany.resources.TestCustomerDatabase</class>
   </alternatives>
</beans>

这很好,很简单,当我们只有一两个bean根据部署场景而变化时。嗯,我通常认为大多数应用程序都是这种情况。然而,那些被Spring框架过度影响的开发者认为他们有数百个bean可能会根据部署而变化。这就是他们为什么要编写大量的XML来显式列出他们应用程序中的所有类。我们当然不想跟随他们走那条路!

因此,CDI提供了定义表示部署场景的注解的能力。这些注解被称为替代 stereotype。例如

@Alternative @Stereotype
@Target(TYPE) @Retention(RUNTIME)
public @interface Mock {}
@Alternative @Stereotype
@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
public @interface Test {}

现在我们可以使用这些注解来指明我们的哪些Bean属于哪个部署场景。

class TestCustomerDatabase {
   static 
   @Resource(lookup="java:global/env/jdbc/TestDatasource") 
   @Produces @Test @CustomerDatabase 
   Datasource testCustomerDatabase;
}
@Mock @CustomerDatabase
class MockCustomerDatabase implements Datasource {
   //operations of Datasource go here!
   ...
}

现在,只需要一行XML,我们就可以一次性启用所有@TestBean,或者所有@MockBean。

<beans>
   <alternatives>
      <stereotype>org.mycompany.deployment.Test</stereotype>
   </alternatives>
</beans>

您不觉得这是一个更好的方法吗?


回到顶部