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 }
View Code

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 }
View Code
 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 }
View Code

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 }
View Code

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 }
View Code

二、动态代理

1.接口

1 package com.zhidi.service;
2 
3 public interface PayService {
4     /*
5      * 支付方法
6      */
7     public boolean pay(String userName,double money);
8  
9 }
View Code

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 }
View Code
 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 }
View Code

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 }
View Code

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 }
View Code

三、基于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 }
View Code

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 }
View Code
 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 }
View Code

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 }
View Code

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 }
View Code

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>
View Code

四、基于@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 }
View Code

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>
View Code

 

原文地址:https://www.cnblogs.com/zclqian/p/7454977.html