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>