public interface Account { public BigDecimal getBalance(); public User getOwner(); public void withdraw(BigDecimal amount); public void deposit(BigDecimal amount); }
几种不同的Bean在我们系统实现账户接口。
然而,我们有一个强制要求:任何类型的账户,交易必须由系统日志进行记录.@Decorator public abstract class LargeTransactionDecorator implements Account { ... }
装饰器的装修类型实现方法,可以让他拦截他想要拦截的.
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; @PersistenceContext EntityManager em; public void withdraw(BigDecimal amount) { ... } public void deposit(BigDecimal amount); ... } }
需要注意的是,一个装饰器可能是一个抽象类. 因此,某些情况下你可能不需要去实现方法.
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; ... }
像上面这段代码,装饰器将绑定到所有实现了Account的Bean上.
如果是下面这段代码,@Foreign是我们自定义.@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Foreign Account account; ... }
decorator可能调用委托对象,和拦截器调用InvocationContext.proceed() 有大致有相同的结果.但主要的区别在于装饰可以委托对象上调用任何业务方法。
@Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; @PersistenceContext EntityManager em; public void withdraw(BigDecimal amount) { account.withdraw(amount); if ( amount.compareTo(LARGE_AMOUNT)>0 ) { em.persist( new LoggedWithdrawl(amount) ); } } public void deposit(BigDecimal amount); account.deposit(amount); if ( amount.compareTo(LARGE_AMOUNT)>0 ) { em.persist( new LoggedDeposit(amount) ); } } }
<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"> <decorators> <class>org.mycompany.myapp.LargeTransactionDecorator</class> </decorators> </beans>
注意:不要即在bean.xml配置又写@Priority.可能会出一些奇怪的问题.根本上,同时用这两种方式就是错误的.