[weld] 专业护理Decorators
wuhaixing
2010-04-26
Interceptors的强大之处在于能够找到共性的问题并分离出来单独解决,无论问题出现在那种Java类型中,都可以交给interceptor去解决。这种方式能完美的解决各种技术问题,包括事务管理、安全性、访问日志等。但interceptor关注的只是要解决的问题本身,他们对于召唤他出来解决问题的bean毫不关心,因此也所知有限。所以,如果要分离解决有共性的业务问题,interceptor就不太合适了。
与interceptor只关心特定的问题不同,decorators只为特定的java interface提供服务,因此她了解她的服务对象,实际上她就是作为其服务接口的实现出现的。所以她很适合与解决具有共性的业务问题,当然也不能要求她像interceptor那么吃得开,适用于所有类型中出现的共同问题。Interceptors 和 decorators虽然很相似,但他们各有所长,互为补充. 先来看个例子: 假定我们要写一个account 接口: public interface Account { public BigDecimal getBalance(); public User getOwner(); public void withdraw(BigDecimal amount); public void deposit(BigDecimal amount); } 在我们的程序中这个接口有几个实现类。但我们希望任何实现类处理大额交易时,都必须在特定的log中做记录。这就是专门为Decorators准备的问题。 decorator也是一个bean,她实现了其所关注的类型(甚至可能是个抽象类),只是多带了个 @Decorator标记。 @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可以不实现。 interceptor方法会在deocorator方法之前调用。 |
|
wuhaixing
2010-04-26
代理对象
Decorators 有一个特殊的注入点,叫做“delegate injection point”, 与其decorate的bean类型一致。这个注入点还要带一个特殊的标记,@Delegate. decorate只能有唯一的代理注入点,可以是构造方法参数、初始化方法参数或注入变量. @Decorator public abstract class LargeTransactionDecorator implements Account { @Inject @Delegate @Any Account account; ... } decorator对满足下面这些条件的bean进行护理:
下面这个delegate injection point表明decorator到所有实现了Account的bean: @Inject @Delegate @Any Account account; 代理注入点可以跟着任意多的qualifier annotations. 只有那些带有相同qualifiers的bean才会被decorate. @Inject @Delegate @Foreign Account account; decorator可以调用代理对象,和interceptor调用InvocationContext.proceed()效果相同,但decorator牛在可以调用代理对象中的任何方法。 @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) ); } } } |
|
wuhaixing
2010-04-26
启用decorators
想干这个也得和interceptor一样去beans.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 http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <decorators> <class>org.mycompany.myapp.LargeTransactionDecorator</class> </decorators> </beans> 和interceptor作用一样,规定顺序,启用禁用。 |