spring AOP
1. 目标类
Waiter
package com.smart.aop.advice.pointcut; public class Waiter { private int age; //省略setter.getter public void greetTo(String name) { System.out.println("Waiter greet to " + name + " ..."); } public void serverTo(String name) { System.out.println("waiter server to " + name + " ..."); } }
Seller
package com.smart.aop.advice.pointcut; public class Seller { private int age; //省略setter.getter public void greetTo(String name) { System.out.println("seller greet to " + name + " ..."); } public void serverTo(String name) { System.out.println("seller server to " + name + " ..."); } }
2. 前置增强类GreetingBeforeAdvice
package com.smart.aop.advice.pointcut; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * 前置增强类 */ public class GreetingBeforeAdvice implements MethodBeforeAdvice { /** * method, 目标类的方法 * args, 目标类方法的入参 * target, 目标类实例 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { //输出切点信息 --- 哪个类的哪个方法 System.out.println("在前置增强中输出切点信息:" + target.getClass().getName() + "." + method.getName()); if (target instanceof Waiter) { Waiter waiter = (Waiter)target; System.out.println("在前置增强中访问目标实例waiter.age=" + waiter.getAge()); } else if (target instanceof Seller) { Seller seller = (Seller) target; System.out.println("在前置增强中访问目标实例seller.age=" + seller.getAge()); } String clientName = (String) args[0]; System.out.println("How are you! Mr." + clientName); } }
3. 静态方法名匹配切面
1 package com.smart.aop.advice.pointcut; 2 3 import java.lang.reflect.Method; 4 import org.springframework.aop.ClassFilter; 5 import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; 6 7 8 /** 9 * 静态方法名匹配切面 10 */ 11 public class GreetingPointcutAdvisor extends StaticMethodMatcherPointcutAdvisor { 12 13 /** 14 * 切点pointcut方法匹配规则 -- 匹配名为greetTo的方法 15 */ 16 @Override 17 public boolean matches(Method method, Class<?> targetClass) { 18 19 //输出切点信息 --- 哪个类的哪个方法 20 System.out.println("在切面的matches方法中输出切点信息:" + targetClass.getName() + "." + method.getName()); 21 22 return "greetTo".equals(method.getName()); 23 } 24 25 /** 26 * 切点类匹配规则 -- 匹配Waiter类及其子类 27 */ 28 public ClassFilter getClassFilter() { 29 return new ClassFilter() { 30 31 @Override 32 public boolean matches(Class<?> clazz) { 33 34 System.out.println("在切面的getClassFilter方法中输出切点信息:" + clazz.getName()); 35 /* 36 * 如果Waiter是clazz参数类型的超类,或clazz本身就是Waiter类型,则返回true 37 * 即仅匹配Waitr类及其子类 38 */ 39 return Waiter.class.isAssignableFrom(clazz); 40 } 41 }; 42 } 43 }
4. 手工编码的方式织入切面生成代理
1 package com.smart.aop.advice.pointcut; 2 3 import org.springframework.aop.framework.ProxyFactory; 4 import org.testng.annotations.BeforeTest; 5 import org.testng.annotations.Test; 6 7 public class PointcutAdvisorTest { 8 9 private Seller sellerTarget; //目标实例 10 private GreetingPointcutAdvisor pointcutAdvisor; //静态方法名切面 11 private ProxyFactory pFactory; //代理工厂 12 13 @BeforeTest 14 public void init() { 15 sellerTarget = new Seller(); 16 pointcutAdvisor = new GreetingPointcutAdvisor(); 17 pFactory = new ProxyFactory(); 18 pFactory.setTarget(sellerTarget); 19 pFactory.addAdvisor(pointcutAdvisor); 20 } 21 22 @Test 23 public void beforeAdvice() { 24 Seller sellerProxy = (Seller) pFactory.getProxy(); 25 sellerProxy.greetTo("john"); 26 } 27 }
输出结果:
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Seller
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Seller
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Seller
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Seller
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Seller
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Seller
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Seller
seller greet to john ...
5.1 使用Spring配置定义切面
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <beans xmlns="http://www.springframework.org/schema/beans" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 6 xsi:schemaLocation=" 7 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 8 "> 9 10 <!-- 目标实例bean --> 11 <bean id="waiterTarget" class="com.smart.aop.advice.pointcut.Waiter" p:age="13"/> 12 <bean id="sellerTarget" class="com.smart.aop.advice.pointcut.Seller" p:age="33"/> 13 <!-- 前置增强 --> 14 <bean id="greetingBeforeAdvice" class="com.smart.aop.advice.pointcut.GreetingBeforeAdvice" /> 15 <!-- 定义一个切面,向其注入前置增强 --> 16 <bean id="greetingPointcutAdvisor" class="com.smart.aop.advice.pointcut.GreetingPointcutAdvisor" 17 p:advice-ref="greetingBeforeAdvice"/> 18 <!-- 定义一个抽象代理bean --> 19 <bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" 20 p:proxyTargetClass="true" 21 p:interceptorNames="greetingPointcutAdvisor" /> 22 <!-- 具体代理 --> 23 <bean id="waiter" parent="parent" p:target-ref="waiterTarget" /> 24 <bean id="seller" parent="parent" p:target-ref="sellerTarget" /> 25
///////////////////////////////
//// 使用上面已定义的目标bean实例(waiterTarget, sellerTarget)和前置增强greetingBeforeAdvice
//// 通过正则表达式,定义一个与上述"静态方法名匹配切面"等价的"正则表达式方法名匹配切面"
26 <!-- 通过正则表达式定义一个切面,即"正则表达式方法名匹配切面" --> 27 <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" 28 p:advice-ref="greetingBeforeAdvice"> 29 <property name="patterns"> 30 <list> 31 <value>.*greet.*</value> 32 </list> 33 </property> 34 </bean> 35 <!-- 定义目标类的代理 --> 36 <bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean" 37 p:proxyTargetClass="true" 38 p:target-ref="waiterTarget" 39 p:interceptorNames="regexpAdvisor" /> 40 <bean id="seller1" class="org.springframework.aop.framework.ProxyFactoryBean" 41 p:proxyTargetClass="true" 42 p:target-ref="sellerTarget" 43 p:interceptorNames="regexpAdvisor" /> 44 </beans>
5.2 测试
1 package com.smart.aop.advice.pointcut; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 import org.testng.annotations.Test; 6 7 public class SpringPointcutAdviceTest { 8 9 @Test 10 public void testAdvice() { 11 12 ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/smart/aop/advice/pointcut/beans-pointcut.xml"); 13 14 Waiter waiter = ctx.getBean("waiter", Waiter.class); //静态方法名匹配切面织入增强逻辑 15 waiter.greetTo("john"); 16 17 Seller seller = ctx.getBean("seller1", Seller.class); //正则表达式方法匹配织入增强逻辑 18 seller.greetTo("jack"); 19 } 20 }
输出结果:
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter
在切面的matches方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter.greetTo
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter
在切面的matches方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter.getAge
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter
在切面的matches方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter.setAge
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter
在切面的matches方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter.serverTo
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter
在切面的matches方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter.toString
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter
在切面的matches方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter.clone
在切面的getClassFilter方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter
在切面的matches方法中输出切点信息:com.smart.aop.advice.pointcut.Waiter.greetTo
在前置增强中输出切点信息:com.smart.aop.advice.pointcut.Waiter.greetTo
在前置增强中访问目标实例waiter.age=13
How are you! Mr.john
Waiter greet to john ...
在前置增强中输出切点信息:com.smart.aop.advice.pointcut.Seller.greetTo
在前置增强中访问目标实例seller.age=33
How are you! Mr.jack
seller greet to jack ...