[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进行护理:
  • 与代理注入点类型一致的bean
  • 带有与代理注入点标记的qualifier完全相同的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作用一样,规定顺序,启用禁用。
Global site tag (gtag.js) - Google Analytics