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就是另一個選擇。<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要先了解以下三個interface:
- org.springframework.aop.Pointcut
- org.springframework.aop.ClassFilter
- 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設定就可以了。
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;
}
}