2013年1月16日 星期三

Programmatic AOP PointCut

我們通常會利用Spring Schema-based AOP support來設定advisor,包含Declarative transaction management大多也會利用AOP來設定:
For example:
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
    <!-- all methods starting with 'get' are read-only -->
    <tx:method name="get*" read-only="true"/>
    <!-- other methods use the default transaction settings (see below) -->
    <tx:method name="*"/>
  </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution of an operation defined by the FooService interface -->
<aop:config>
  <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
但有時pointcut expression不見得容易下,尤其是要找出或是排除一些特殊的class/interface signature時,就不見得那麼好處理,往往會讓expression的設定變的很長,此時利用programmatic的方式來宣告pointcut就是另一個選擇。

要自己實作pointcut要先了解以下三個interface:
  1. org.springframework.aop.Pointcut
  2. org.springframework.aop.ClassFilter
  3. org.springframework.aop.MethodMatcher
我們可以用一個class同時implement這三個interface,減少一些class的數量,然後在程式裡依照自己想要攔截的物件特性進行實作。
Example:
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;

/**
 * @author linus_chien
 *
 */
public class SimplePointCut implements Pointcut, ClassFilter, MethodMatcher {

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return true;
    }

    @Override
    public boolean isRuntime() {
        return false;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass, Object[] args) {
        return true;
    }

    @Override
    public boolean matches(Class<?> clazz) {
        return true;
    }

    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }

}
最後在Spring XML裡面宣告這個bean instance取代原本pointcut設定就可以了。