CDI(Weld)高级<6> Specialization and alternatives

当多个版本的bean来实现不同的目的,在开发过程中,需要在多个Bean版本之间切换.而不必更改源代码的应用程序,可以选择在部署时使用 @Alternative
CDI @Alternative方案通常用于以下目的,如:
1.     为了处理客户特定的业务逻辑在运行时确定。
2.     要指定Bean的有效期为一个特定的部署方案,例如,特定国家的销售税的法律时,需要针对具体国家的销售税业务逻辑。
3.     用于测试的模拟版本。
这个情况下本章的 @Alternative 和 @Specializes内容就是你要学习的.

1. Using alternative stereotypes

CDI允许在部署时使用替代的实现去覆盖一个bean类型。
例如,下面bean提供了PaymentProcessor接口的默认实现:.
public class DefaultPaymentProcessor implements PaymentProcessor {
   ...
}

但在我们的环境中,我们不想使用这个默认的实现,所以我们重写了PaymentProcessor:

@Alternative
public class StagingPaymentProcessor implements PaymentProcessor {
   ...
}

或者

@Alternative
public class StagingPaymentProcessor extends DefaultPaymentProcessor {
   ...
}

在bean.xml中进行配置

<beans xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee">
    <alternatives>
        <class>org.credo.StagingPaymentProcessor</class>
    </alternatives>
</beans>

这样就在项目启动的时候使用了指定的实现.

但不可能一个个的在bean.xml中配置.CDI提供了更方便的方法.如下
先定义一个Stereotype,注意,其包含了@Alternative注解.
@Alternative
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Staging {}

在我们这个环境要使用的Bean实现上加@Staging Stereotype注解.

@Staging
public class StagingPaymentProcessor implements PaymentProcessor {
   ...
}

最后我们在bean.xml中仅需如此配置

<beans
   xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
      http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
   <alternatives>
         <stereotype>org.mycompany.myapp.Staging</stereotype>
   </alternatives>
</beans>

现在不管有多少Staging环境下使用的替换Bean,他们都将全部启动.

2.alternatives的一个非严重缺陷

当我们启用替代方案,这是否意味着默认的实现被禁用?不完全是!
如果默认的实现有一个限定词,例如@LargeTransaction ,alternatives Bean没有,系统仍然会注入的默认实现.例如
@Inject @LargeTransaction PaymentProcessor paymentProcessor;

所以我们在系统中还没有完全取代该默认实现,一个alternatives Bean在所有注射点可以完全重写默认bean的唯一方法是alternatives Bean实现所有bean类型,所有限定符。比如上面PaymentProcessor 的alternatives Bean也加入了@LargeTransaction注解.

但是,如果默认的Bean申明了一个producer方法或者一个观察者方法(cdi event 事件),那么即时是如上述所说的那样做,也还是不够的.我们需要进行额外的一些处理.

CDI提供了一个特殊的功能,叫做specialization(专业化),可以帮助开发者避免这些陷阱。specialization是通知系统的方式来完全替代和禁用一个bean的实现。

3.Using specialization

针对第二节的问题,使用@Specializes来处理,如下所示:

@Alternative @Specializes
public class MockCreditCardPaymentProcessor
      extends CreditCardPaymentProcessor {
   ...
}

当启用了这个Alternative Bean,即时其他的Bean,包括默认的Bean,申明了Producer方法和观察者方法,依然使用这个Alternative Bean.


这个时候,我们通知容器,我们必须使用这个Alternative Bean,这个Alternative Bean也会自动继承默认实现的所有qualifiers.
比如默认Bean有 @Default @CreditCard,那么例子的MockCreditCardPaymentProcessor也会继承这2个限定符.
比如默认Bean是有@Named,那么MockCreditCardPaymentProcessor会使用默认的EL Name.相当于继承了@Named!




你可能感兴趣的:(CDI(Weld)高级<6> Specialization and alternatives)