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提供了更方便的方法.如下@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,他们都将全部启动.
@Inject @LargeTransaction PaymentProcessor paymentProcessor;
所以我们在系统中还没有完全取代该默认实现,一个alternatives Bean在所有注射点可以完全重写默认bean的唯一方法是alternatives Bean实现所有bean类型,所有限定符。比如上面PaymentProcessor 的alternatives Bean也加入了@LargeTransaction注解.
但是,如果默认的Bean申明了一个producer方法或者一个观察者方法(cdi event 事件),那么即时是如上述所说的那样做,也还是不够的.我们需要进行额外的一些处理.CDI提供了一个特殊的功能,叫做specialization(专业化),可以帮助开发者避免这些陷阱。specialization是通知系统的方式来完全替代和禁用一个bean的实现。
针对第二节的问题,使用@Specializes来处理,如下所示:
@Alternative @Specializes public class MockCreditCardPaymentProcessor extends CreditCardPaymentProcessor { ... }
当启用了这个Alternative Bean,即时其他的Bean,包括默认的Bean,申明了Producer方法和观察者方法,依然使用这个Alternative Bean.