通过Advice,可以创建方法前,后,环绕之类的增强,但是这是类级别的增强,如果想要深入到方法级别,就需要配合使用切点Pointcut。Advice和Pointcut组合就形成了一个切面。切面增强就是基于方法层面的。
1.切点(Pointcut)
用于过滤类,getClassFilter()返回ClassFilter类,在这个类里面有一个方法用于判断该对象是否满足匹配条件,boolean matches(Class> clazz)。
用于过滤方法,getMethodMatcher()返回MethodMatcher,在该类里面有boolean matches(Method method, Class> targetClass)用于静态匹配方法,boolean matches(Method method, Class> targetClass, Object[] args)用于动态匹配。
2 切点的分类
- StaticMethodMatcherPointcut 静态方法切点
- DynamicMethodMatcherPointcut 动态方法切点
- AnnotationMatchingPointcut 注解切点
- AspectJExpressionPointcut 支持AspectJ语法的表达式切点
- ControlFlowPointcut 流程切点
- ComposablePointcut 复合切点
静态方法切点又分两种
- NameMatchMethodPointcut 用于方法名匹配
- JdkRegexpMethodPointcut 用于正则匹配
3 切面
切面分三种
- Advisor 一般切面,仅包含一个增强方法,不包含切点信息
- PointcutAdvisor 包含切点的切面,用起来比较灵活
- IntroductionAdvisor 引介切面
而PointcutAdvisor又分为以下6种
- DefaultPointcutAdvisor 最常用的切面,可以通过任意组合切点和增强构建切面
- NameMatchMethodPointcutAdvisor 通过方法名来定义切面
- RegexpMethodPointcutAdvisor 通过正则表达式匹配方法名来定义切面
- StaticMethodMatcherPointcutAdvisor 默认情况下,匹配所有目标类
- AspectJExpressionPointcutAdvisor 用AspectJ切点表达式来匹配
- AspectJPointcutAdvisor 用AspectJ语法来匹配
4 例子
准备基础类和一个增强类
public class Waiter { public void greetTo(String name) { System.out.println("waiter greet to " + name + "..."); } public void serveTo(String name) { System.out.println("waier serving to " + name + "..."); } } public class Seller { public void greetTo(String name) { System.out.println("seller greet to " + name + "..."); } }个 // 前置增强 public class GreetingBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object obj) throws Throwable { System.out.println(obj.getClass().getName() + "." + method.getName()); String clientName = (String) args[0]; System.out.println("How are you! Mr." + clientName); } }
4.1 静态方法匹配:
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor { public boolean matches(Method method, Class> targetClass) { return "greetTo".equals(method.getName()); } public ClassFilter getClassFilter() { return new ClassFilter() { public boolean matches(Class> clazz) { return Waiter.class.isAssignableFrom(clazz); } }; } }
因为GreetingAdvisor类中已经包含切点信息,所以只要配置增强类即可。
测试:
String configPath = "com/firethewhole/maventest07/advisor/beans.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath); Waiter waiter = (Waiter) ctx.getBean("waiter"); Seller seller = (Seller) ctx.getBean("seller"); waiter.greetTo("John"); waiter.serveTo("John"); seller.greetTo("John");
输出:
只有Waiter类的greetTo方法被织入增强
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.John
waiter greet to John...
waier serving to John...
seller greet to John...
4.2 正则匹配方法名增强
.*greet.*
Waiter waiter1 = (Waiter) ctx.getBean("waiter1"); waiter1.greetTo("John"); waiter1.serveTo("John");
输出:
只有greetTo方法被织入增强
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.John
waiter greet to John...
waier serving to John...
4.3 动态方法匹配
动态方法匹配之前都会先进性静态方法匹配,如果失败才会进行
public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut { private static ListspecialClientList = new ArrayList (); static { specialClientList.add("John"); specialClientList.add("Tom"); } public ClassFilter getClassFilter() { return new ClassFilter() { public boolean matches(Class> clazz) { System.out.println("调用getClassFilter()对" + clazz.getName() + "做静态检查。"); return Waiter.class.isAssignableFrom(clazz); } }; } public boolean matches(Method method, Class> clazz) { System.out.println("调用matches(method,clazz)对" + clazz.getName() + "." + method.getName() + "做静态检查。"); return "greetTo".equals(method.getName()); } public boolean matches(Method method, Class> clazz, Object[] args) { System.out.println("调用matches(method,clazz)对" + clazz.getName() + "." + method.getName() + "做动态检查。"); String clientName = (String) args[0]; return specialClientList.contains(clientName); } }
Waiter waiter2 = (Waiter) ctx.getBean("waiter2"); waiter2.greetTo("Peter"); waiter2.serveTo("Peter"); waiter2.greetTo("John"); waiter2.serveTo("John");
输出:
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.serveTo做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.toString做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.clone做静态检查。
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做动态检查。
waiter greet to Peter...
调用getClassFilter()对com.firethewhole.maventest07.advisor.Waiter做静态检查。
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.serveTo做静态检查。
waier serving to Peter...
调用matches(method,clazz)对com.firethewhole.maventest07.advisor.Waiter.greetTo做动态检查。
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.John
waiter greet to John...
waier serving to John...
4.4 流程切面
对配置在某一个类中的某一个方法中直接或间接使用的类进行增强
public class WaiterDelegate { private Waiter waiter; public void setWaiter(Waiter waiter) { this.waiter = waiter; } public void service(String name) { waiter.greetTo(name); waiter.serveTo(name); } }
Waiter waiter3 = (Waiter) ctx.getBean("waiter3"); WaiterDelegate wd = new WaiterDelegate(); wd.setWaiter(waiter3); waiter3.serveTo("Peter"); waiter3.greetTo("Peter"); wd.service("Peter");
输出:
只有流程切点中的才会被织入增强
waier serving to Peter...
waiter greet to Peter...
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.Peter
waiter greet to Peter...
com.firethewhole.maventest07.advisor.Waiter.serveTo
How are you! Mr.Peter
waier serving to Peter...
4.5 复合增强
public class GreetingComposablePointcut { public Pointcut getIntersectionPointcut() { ComposablePointcut cp = new ComposablePointcut(); Pointcut pt1 = new ControlFlowPointcut(WaiterDelegate.class, "service"); Pointcut pt2 = new NameMatchMethodPointcut(); ((NameMatchMethodPointcut)pt2).addMethodName("greetTo"); return cp.intersection(pt1).intersection(pt2); } }
Waiter waiter4 = (Waiter) ctx.getBean("waiter4"); WaiterDelegate wd2 = new WaiterDelegate(); wd2.setWaiter(waiter4); waiter4.serveTo("Peter"); waiter4.greetTo("Peter"); wd2.service("Peter");
输出:
只有流程切点中的方法名为greetTo才会被织入增强
waier serving to Peter...
waiter greet to Peter...
com.firethewhole.maventest07.advisor.Waiter.greetTo
How are you! Mr.Peter
waiter greet to Peter...
waier serving to Peter...
4.6 引介增强
引介增强是类级别的织入,主要的类有DefaultIntroductionAdvisor,配置方法如下:
- maventest07.zip (56.3 KB)
- 下载次数: 0