一、静态代理
1.接口
1 package com.zhidi.service; 2 3 public interface PayService { 4 /* 5 * 支付方法 6 */ 7 public boolean pay(String userName,double money); 8 9 }
2.目标对象(实现接口)
1 package com.zhidi.service.imp; 2 3 import com.zhidi.service.PayService; 4 /* 5 * 目标对象 6 */ 7 public class QQPayService implements PayService { 8 9 @Override 10 public boolean pay(String userName, double money) { 11 12 System.out.println(userName+"用QQ支付了"+money+"块钱"); 13 return true; 14 } 15 16 }
1 package com.zhidi.service.imp; 2 3 import com.zhidi.service.PayService; 4 /* 5 * 目标对象 6 */ 7 public class WxPayService implements PayService { 8 9 @Override 10 public boolean pay(String userName, double money) { 11 System.out.println(userName+"用微信支付了"+money+"块钱"); 12 return true; 13 } 14 15 }
3.代理类(实现接口)
1 package com.zhidi.service.proxy; 2 3 import com.zhidi.service.PayService; 4 /* 5 * 静态代理类 6 */ 7 public class PayServiceProxy implements PayService { 8 //引用目标对象 9 private PayService target; 10 11 public PayServiceProxy(PayService target) { 12 this.target = target; 13 } 14 15 @Override 16 public boolean pay(String userName, double money) { 17 before(userName, money); 18 //调用目标对象的pay方法完成支付 19 boolean result=target.pay(userName, money); 20 after(userName, money, result); 21 return result; 22 } 23 24 //增加额外的功能 25 public void before(String userName, double money) 26 { 27 System.out.println(userName+"准备用"+money+"钱"); 28 } 29 30 public void after(String userName, double money,boolean result) 31 { 32 if(result) 33 { 34 System.out.println("用钱成功"); 35 }else 36 { 37 System.out.println("用钱失败"); 38 } 39 } 40 }
4.测试
1 package com.zhidi.service.test; 2 3 4 import com.zhidi.service.imp.QQPayService; 5 import com.zhidi.service.proxy.PayServiceProxy; 6 7 public class TestStaticProxy { 8 public static void main(String[] args) { 9 //创建代理对象并为其指定代理的目标对象 10 PayServiceProxy proxy=new PayServiceProxy(new QQPayService()); 11 proxy.pay("尼古拉斯·赵四", 20000); 12 } 13 14 }
二、动态代理
1.接口
1 package com.zhidi.service; 2 3 public interface PayService { 4 /* 5 * 支付方法 6 */ 7 public boolean pay(String userName,double money); 8 9 }
2.目标对象
1 package com.zhidi.service.imp; 2 3 import com.zhidi.service.PayService; 4 /* 5 * 目标对象 6 */ 7 public class QQPayService implements PayService { 8 9 @Override 10 public boolean pay(String userName, double money) { 11 12 System.out.println(userName+"用QQ支付了"+money+"块钱"); 13 return true; 14 } 15 16 }
1 package com.zhidi.service.imp; 2 3 import com.zhidi.service.PayService; 4 /* 5 * 目标对象 6 */ 7 public class WxPayService implements PayService { 8 9 @Override 10 public boolean pay(String userName, double money) { 11 System.out.println(userName+"用微信支付了"+money+"块钱"); 12 return true; 13 } 14 15 }
3.代理类
1 package com.zhidi.service.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 import com.zhidi.service.PayService; 7 8 /* 9 * 动态代理 10 */ 11 public class DynamicServiceProxy implements InvocationHandler { 12 //目标对象 13 private PayService payService; 14 15 public DynamicServiceProxy(PayService payService) { 16 this.payService = payService; 17 } 18 19 @Override 20 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 21 //参数在args数组中 22 before((String) args[0], (double) args[1]); 23 //调用目标对象的目标方法 24 Object result = method.invoke(payService, args); 25 after((String) args[0], (double) args[1], (boolean) result); 26 return result; 27 } 28 29 // 增加额外的功能 30 public void before(String userName, double money) { 31 System.out.println(userName + "准备用" + money + "钱"); 32 } 33 34 public void after(String userName, double money, boolean result) { 35 if (result) { 36 System.out.println("用钱成功"); 37 } else { 38 System.out.println("用钱失败"); 39 } 40 } 41 42 }
4.测试
1 package com.zhidi.service.test; 2 3 import java.lang.reflect.Proxy; 4 5 import com.zhidi.service.PayService; 6 import com.zhidi.service.imp.QQPayService; 7 import com.zhidi.service.proxy.DynamicServiceProxy; 8 9 public class TestDynamicProxy { 10 public static void main(String[] args) { 11 // proxy的newProxyInstance()方法用于为目标对象创建代理对象,目标对象和代理对象实现相同的接口 12 // ClassLoader loader:类加载器 13 // interfacers:目标对象实现的接口 14 // h:代理对象通过该对象实现对目标的增强 15 PayService proxy = (PayService) Proxy.newProxyInstance(TestDynamicProxy.class.getClassLoader(), 16 new Class[] { PayService.class }, new DynamicServiceProxy(new QQPayService())); 17 18 proxy.pay("刘能", 20000); 19 } 20 21 }
三、基于xml的Spring AOP
1.接口
1 package com.zhidi.service; 2 3 public interface PayService { 4 /* 5 * 支付方法 6 */ 7 public boolean pay(String userName,double money); 8 9 }
2.目标对象
1 package com.zhidi.service.imp; 2 3 import com.zhidi.service.PayService; 4 /* 5 * 目标对象 6 */ 7 public class QQPayService implements PayService { 8 9 @Override 10 public boolean pay(String userName, double money) { 11 12 System.out.println(userName+"用QQ支付了"+money+"块钱"); 13 return true; 14 } 15 16 }
1 package com.zhidi.service.imp; 2 3 import com.zhidi.service.PayService; 4 /* 5 * 目标对象 6 */ 7 public class WxPayService implements PayService { 8 9 @Override 10 public boolean pay(String userName, double money) { 11 System.out.println(userName+"用微信支付了"+money+"块钱"); 12 return true; 13 } 14 15 }
3.通知类
1 package com.zhidi.advice; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 5 /* 6 * 通知类 7 */ 8 public class LogAdvice { 9 10 //前置通知 11 public void before() 12 { 13 System.out.println("前置通知"); 14 } 15 //后置通知 16 public void after() 17 { 18 System.out.println("后置通知"); 19 } 20 //带参数的前置通知 21 public void beforeLog(String userName, double money) 22 { 23 System.out.println(userName+"准备用"+money+"钱"); 24 } 25 //带参数的后置返回通知 26 public void afterLog(String userName, double money,boolean result) 27 { 28 if(result) 29 { 30 System.out.println("用钱成功"); 31 }else 32 { 33 System.out.println("用钱失败"); 34 } 35 } 36 //异常返回通知,是有参的, 37 public void afterThrowing(Exception e) 38 { 39 System.out.println(e.getMessage()); 40 } 41 //后通知,无论什么情况都会执行的, 42 public void afterFinally() 43 { 44 System.out.println("最终返回通知,无论怎样都会执行"); 45 } 46 //环绕通知,是有返回值的,不需要设置 47 public Object around(ProceedingJoinPoint joinPoint) throws Throwable 48 { 49 //环绕前通知 50 System.out.println("环绕前通知"); 51 Object result= joinPoint.proceed(); 52 //环绕后通知 53 System.out.println("环绕后通知"); 54 return result; 55 } 56 57 }
4.测试
1 package com.zhidi.service.test; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 import com.zhidi.service.PayService; 7 8 public class TestAop { 9 10 public static void main(String[] args) { 11 ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); 12 //通过id获得指定的目标对象 13 PayService payService= context.getBean("wxPayService",PayService.class); 14 payService.pay("黄老邪", 30000); 15 } 16 }
5.applicationContext.xml配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd 7 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> 8 <!-- 将目标对象交给Spring的IOC容器管理 --> 9 <bean id="QQPayService" class="com.zhidi.service.imp.QQPayService" /> 10 <bean id="wxPayService" class="com.zhidi.service.imp.WxPayService" /> 11 <!-- 将切面支持类纳入Spring的IoC容器管理 ,该类中定义通知实现方法 --> 12 <bean id="logAdvice" class="com.zhidi.advice.LogAdvice" /> 13 <!-- aop定义开始 --> 14 <aop:config> 15 <!-- 定义全局切入点,该切入点可以应用于多个切面定义中 expression="execution(public boolean com.zhidi.service.imp.QQPayService.pay(java.lang.String,java.lang.Double)) --> 16 <aop:pointcut expression="execution(* com.zhidi.service..*.pay(..))" 17 id="pointcut" /> 18 <!-- 定义切面,同时指定该切面所需的切面支持类(通知所在类) --> 19 <aop:aspect ref="logAdvice"> 20 <!-- 定义前置通知, --> 21 <aop:before method="before" pointcut-ref="pointcut" /> 22 <!-- 后置返回通知 --> 23 <aop:after-returning method="after" pointcut-ref="pointcut" /> 24 <!-- 前置通知,带有参数 --> 25 <aop:before method="beforeLog" 26 pointcut="execution(* com.zhidi.service..*.pay(..)) and args(userName,money)" 27 arg-names="userName,money" /> 28 <!-- 带参数的后置返回通知 --> 29 <aop:after-returning method="afterLog" 30 pointcut="execution(* com.zhidi.service..*.pay(..)) and args(userName,money)" 31 returning="result" arg-names="userName,money,result" /> 32 <!-- 异常返回通知 --> 33 <aop:after-throwing method="afterThrowing" 34 pointcut-ref="pointcut" throwing="e" /> 35 <!-- 后通知 --> 36 <aop:after method="afterFinally" pointcut-ref="pointcut" /> 37 <!-- 环绕通知 --> 38 <aop:around method="around" pointcut-ref="pointcut" /> 39 </aop:aspect> 40 </aop:config> 41 42 </beans>
四、基于@AspectJ风格的AOP(接口、目标对象和测试以上一样)
1.通知类
1 package com.zhidi.advice; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 import org.aspectj.lang.annotation.After; 5 import org.aspectj.lang.annotation.AfterReturning; 6 import org.aspectj.lang.annotation.AfterThrowing; 7 import org.aspectj.lang.annotation.Around; 8 import org.aspectj.lang.annotation.Aspect; 9 import org.aspectj.lang.annotation.Before; 10 import org.springframework.stereotype.Component; 11 12 /* 13 * 通知类 14 */ 15 //基于@Aspect的AOP 16 @Component // 将当前的Bean交给Spring的IOC容器管理 17 @Aspect // 将该Bean定义为切面 18 public class LogAonnection { 19 20 // 前置通知 21 @Before("execution(* com.zhidi.service..*.*(..))") 22 public void before() { 23 System.out.println("前置通知"); 24 } 25 26 // 后置通知 27 @AfterReturning("execution(* com.zhidi.service..*.*(..))") 28 public void after() { 29 System.out.println("后置通知"); 30 } 31 32 // 带参数的前置通知 33 @Before(value = "execution(* com.zhidi.service..*.*(..)) and args(userName,money)", argNames = "userName,money") 34 public void beforeLog(String userName, double money) { 35 System.out.println(userName + "准备用" + money + "钱"); 36 } 37 38 // 带参数的后置返回通知 39 @AfterReturning(value = "execution(* com.zhidi.service..*.*(..)) and args(userName,money)", returning = "result", argNames = "userName,money,result") 40 public void afterLog(String userName, double money, boolean result) { 41 if (result) { 42 System.out.println("用钱成功"); 43 } else { 44 System.out.println("用钱失败"); 45 } 46 } 47 48 // 异常返回通知,是有参的, 49 @AfterThrowing(value = "execution(* com.zhidi.service..*.*(..))", throwing = "e") 50 public void afterThrowing(Exception e) { 51 System.out.println(e.getMessage()); 52 } 53 54 // 后通知,无论什么情况都会执行的, 55 @After(value = "execution(* com.zhidi.service..*.*(..))") 56 public void afterFinally() { 57 System.out.println("最终返回通知,无论怎样都会执行"); 58 } 59 60 // 环绕通知,是有返回值的,不需要设置 61 @Around(value = "execution(* com.zhidi.service..*.*(..))") 62 public Object around(ProceedingJoinPoint joinPoint) throws Throwable { 63 // 环绕前通知 64 System.out.println("环绕前通知"); 65 Object result = joinPoint.proceed(); 66 // 环绕后通知 67 System.out.println("环绕后通知"); 68 return result; 69 } 70 71 }
2.applicationContext.xml配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd 7 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> 8 <!-- 开启注解配置 --> 9 <context:component-scan base-package="com.zhidi"/> 10 <!-- aspectj注解配置 --> 11 <aop:aspectj-autoproxy/> 12 <!-- 将目标对象交给Spring的IOC容器管理 --> 13 <bean id="QQPayService" class="com.zhidi.service.imp.QQPayService" /> 14 <bean id="wxPayService" class="com.zhidi.service.imp.WxPayService" /> 15 16 17 </beans>