Spring AOP 的底層實現機制
2. Spring AOP 中的 Pointcut
6. 擴展 Pointcut
如何前面的 Pointcut 類型都無法滿足要求,這種情況下可以擴展 Spring AOP 的 Pointcut ,給出自定義的 Pointcut。
要自定義 Pointcut ,Spring AOP 已經提供了相應的擴展抽象支持,我們只需要繼承相應的抽象父類,然後實現或者覆寫
方法邏輯即可。
Spring AOP 的 Pointcut 類型可以劃分爲 StaticMethodMatcherPointcut 和 DynamicMethodMatcherPointcut
自定義 Pointcut 只需要在這兩個抽象類的基礎上實現相應子類即可。
a. StaticMethodMatcherPointcut
package org.springframework.aop.support;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
/**
* 因爲是 StaticMethodMatcher,所以其 MethodMatcher 的 isRuntime 方法返回 false,
* 同時三個參數的 matches 方法拋出 UnsupportedOperationException 異常,
* 以表示該方法不應該被調用到。(該部分在 抽象父類 StaticMethodMatcher 中實現)
*
*/
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
private ClassFilter classFilter = ClassFilter.TRUE;
/**
* 默認子類的 ClassFilter 均爲 ClassFilter.TRUE,即忽略類的類型匹配。
*/
public ClassFilter getClassFilter() {
return this.classFilter;
}
/**
* 如果子類需要對目標對象的類型做進一步的限制,可以通過該方法設置相應的 ClassFilter 實現
* @param classFilter
*/
public void setClassFilter(ClassFilter classFilter) {
this.classFilter = classFilter;
}
public final MethodMatcher getMethodMatcher() {
return this;
}
}
最終實現 自定義的StaticMethodMatcherPointcut 只需要實現兩個參數的 matches 方法即可。
例如:提供一個 Pointcut , 用來撲捉系統中數據訪問對象中的查詢方法。
package prx.aop.pointcut;
import java.lang.reflect.Method;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
public class QueryMethodPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method method, Class<?> targetClass) {
return method.getName().startsWith("query")
&& targetClass.getPackage().getName().contains("dao");
}
}
b. DynamicMethodMatcherPointcut
package org.springframework.aop.support;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
/**
* 因爲是 DynamicMethodMatcher,所以其 MethodMatcher 的 isRuntime 方法返回 true,
* 同時兩個參數的 matches 也返回 true,以便三個參數的方法順利執行
* (該部分在 抽象父類 DynamicMethodMatcher 中實現)
*/
public abstract class DynamicMethodMatcherPointcut extends DynamicMethodMatcher implements Pointcut {
/**
* 默認子類的 ClassFilter 均爲 ClassFilter.TRUE,即忽略類的類型匹配。
* 如果需要特定的目標對象類型限定,需要覆蓋這個方法。
*/
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
public final MethodMatcher getMethodMatcher() {
return this;
}
}
最終實現自定義的 DynamicMethodMatcherPointcut 只需要實現三個參數的 matches 方法即可。
例如:有個查詢只有 Boss 才能訪問。
package prx.aop.pointcut;
import java.lang.reflect.Method;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;
public class BossQueryMethodPointcut extends DynamicMethodMatcherPointcut {
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
if(method.getName().startsWith("query")
&& targetClass.getPackage().getName().contains("dao")) {
if(args != null && args.length > 1) {
return "Boss".equals(args[0]);
}
}
return false;
}
}
如果願意,也可以覆蓋 兩個參數的 matches 方法,這樣,不用每次都得到三個參數的 matches 方法執行的時候才檢查
所有的條件。
將 Pointcut 加入 IoC 容器中
選擇好了 Pointcut ,剩下就是 將它們加入Spring IoC 容器中,以便 Spring 管理。 Spring 中的 Pointcut 實現都是
普通的 Java 對象, 所以想普通的 POJO 那樣配置注入就可以了。
<bean id="nameMatchPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut"> <property name="mappedNames"> <list> <value>methodName1</value> <value>methodName2</value> </list> </property> </bean>