Spring AOP 5种通知与java动态代理

接口,要求为每个方法前后添加日志 
 1 @Component("arithmeticCalculator")
 2 public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
 3 
 4     @Override
 5     public int add(int i, int j) {
 6         int result = i + j;
 7         return result;
 8     }
 9 
10     @Override
11     public int sub(int i, int j) {
12         int result = i - j;
13         return result;
14     }
15 
16     @Override
17     public int mul(int i, int j) {
18         int result = i * j;
19         return result;
20     }
21 
22     @Override
23     public int div(int i, int j) {
24         int result = i / j;
25         return result;
26     }
27 
28 }
接口的实现类
 1 public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {
 2 
 3     
 4     @Override
 5     public int add(int i, int j) {
 6         System.out.println("The method add begins with [" + i + "," + j + "]");
 7         int result = i + j;
 8         System.out.println("The method add ends with " + result);
 9         return result;
10     }
11 
12     @Override
13     public int sub(int i, int j) {
14         System.out.println("The method sub begins with [" + i + "," + j + "]");
15         int result = i - j;
16         System.out.println("The method sub ends with " + result);
17         return result;
18     }
19 
20     @Override
21     public int mul(int i, int j) {
22         System.out.println("The method mul begins with [" + i + "," + j + "]");
23         int result = i * j;
24         System.out.println("The method mul ends with " + result);
25         return result;
26     }
27 
28     @Override
29     public int div(int i, int j) {
30         System.out.println("The method div begins with [" + i + "," + j + "]");
31         int result = i / j;
32         System.out.println("The method div ends with " + result);
33         return result;
34     }
35 
36 }
方法一:手动实现为方法添加日志
 1 public class ArithmeticCalculatorLoggingProxy {
 2     
 3     
 4     private ArithmeticCalculator target;
 5     
 6     public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
 7         super();
 8         this.target = target;
 9     }
10 
11 
12     public ArithmeticCalculator getLoggingProxy(){
13         ArithmeticCalculator proxy = null;
14         
15         ClassLoader loader = target.getClass().getClassLoader();
16         Class [] interfaces = new Class[]{ArithmeticCalculator.class};
17         InvocationHandler h = new InvocationHandler() {
18             /*method 方法
19              *args 参数 
20              * */
21             @Override
22             public Object invoke(Object proxy, Method method, Object[] args)
23                     throws Throwable {
24                 String methodName = method.getName();
25                 
26                 //前置通知
27                 System.out.println("[before] The method " + methodName + " begins with " + Arrays.asList(args));
28                 
29                 Object result = null;
30                 try {
31                     
32                     result = method.invoke(target, args);//返回通知
33                     
34                 } catch (NullPointerException e) {
35                     e.printStackTrace();
36                     //异常通知
37                 }
38                 //后置通知
39                 System.out.println("[after] The method ends with " + result);
40                 
41                 return result;
42             }
43         };
44         
45         proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
46         
47         return proxy;
48     }
49 }
方法二:利用动态代理模式实现为方法添加日志
 1 /**
 2  * AOP 
 3  * 1. 导入jar包
 4  * com.springsource.net.sf.cglib-2.2.0.jar
 5  * com.springsource.org.aopalliance-1.0.0.jar
 6  * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
 7  * spring-aspects-4.0.0.RELEASE.jar
 8  * 
 9  * 2. 在配置文件中加入AOP的命名空间
10  * xmlns:aop="http://www.springframework.org/schema/aop"
11  * 
12  * 3. 基于注解的方式
13  * <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>
14  * <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
15  *  
16  * 4.把横切关注点的代码抽象到切面的类中
17  *   @Aspect
18  *     @Component
19  *     public class LoggingAspect {}
20  *
21  * 5.AspectJ支持5种类型的通知注解
22  *   @Before()前置通知,在方法开始前执行
23  *   @After()后置通知,在方法执行后执行,无论抛异常都会执行;不能访问方法执行的结果
24  *   @AfterRunning()返回通知,在方法返回结果后执行(即方法正常结束后才执行);可以得到方法执行的结果
25  *   @AfterThrowing()异常通知,在方法抛出异常时执行
26  *   @Around()环绕通知,围绕着方法执行
27  * 6.AspectJ表达式
28  *  execution(public int com.aop.beans.ArithmeticCalculator.*(int, int)) 
29  *  execution(* com.aop.beans.*.*(int, int))
30  *  
31  * 7.JoinPoint
32  * 通过他可以得到方法的信息
33  */
34 
35 //把这个类放入到IOC容器中@Component;再声明为一个切面@Aspect
36 @Aspect
37 @Component
38 public class LoggingAspect {
39     //该方法是一个前置通知,即在目标方法开始前执行@Before()
40     @Before("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")
41     public void beforeMethod(JoinPoint joinPoint){
42         String methodName = joinPoint.getSignature().getName();//得到方法名
43         Object [] args = joinPoint.getArgs();//得到参数
44         
45         System.out.println("前置通知:The method " + methodName + " begins with " + Arrays.asList(args));
46     }
47     
48     @After("execution(* com.aop.beans.*.*(..))")//位置为这个包下的所有类、所有方法、不论参数是什么类型
49     public void afterMethod(JoinPoint joinPoint){
50         String methodName = joinPoint.getSignature().getName();
51         System.out.println("后置通知:The method " + methodName + " ends");
52     }
53     
54     
55     @AfterReturning(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",
56             returning="result")
57     public void afterReturning(JoinPoint joinPoint, Object result){
58         String methodName = joinPoint.getSignature().getName();
59         System.out.println("返回通知:The method " + methodName + " ends with " + result);
60     }
61     
62 
63     @AfterThrowing(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",
64             throwing="e")
65     public void afterThrowing(JoinPoint joinPoint, Exception e){
66         String methodName = joinPoint.getSignature().getName();
67         System.out.println("异常通知:The method " + methodName + " occurs excetion:" + e);
68     }
69     
70     /*
71      * 环绕通知功能相当于动态代理的全过程,需要有ProceedingJoinPoint 类型的参数;
72      * pjd 参数可以决定是否执行目标方法
73      * 环绕通知必须有返回值,返回值即为目标方法的返回值
74      * 
75      * 
76     @Around("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")
77     public Object aroundMethod(ProceedingJoinPoint pjd){
78         
79         Object result = null;//返回值
80         String methodName = pjd.getSignature().getName();//得到方法名
81         
82         try {
83             //前置通知
84             System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
85             result = pjd.proceed();//执行方法 //返回通知
86             System.out.println("The method " + methodName + " ends with " + result);
87         } catch (Throwable e) {
88             //异常通知
89             System.out.println("The method " + methodName + " occurs exception:" + e);
90             throw new RuntimeException(e);
91         }
92         //后置通知
93         System.out.println("The method " + methodName + " ends");
94         
95         return result;
96     }
97     */
98     
99 }
方法三:利用Spring AOP AspectJ实现为方法添加日志
 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" 
 4     xmlns:aop="http://www.springframework.org/schema/aop"
 5     xmlns:context="http://www.springframework.org/schema/context"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 7         http://www.springframework.org/schema/beans/spring-beans.xsd
 8         http://www.springframework.org/schema/aop 
 9         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
10         http://www.springframework.org/schema/context 
11         http://www.springframework.org/schema/context/spring-context-4.0.xsd">
12 
13     <!-- 自动扫描的包;  扫描@注解,添加到IOC容器中,让Spring管理-->
14     <context:component-scan base-package="com.aop.beans"></context:component-scan>
15 
16     <!-- 使 AspectJ 的注解起作用 ; autoproxy自动代理-->
17     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
18 
19 </beans>
beans-aop.xml
 1 public class Main {
 2     
 3     public static void main(String[] args) {
 4         /*代理模式实现添加日志功能
 5         ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl();        
 6         arithmeticCalculator = new ArithmeticCalculatorLoggingProxy(arithmeticCalculator).getLoggingProxy();        
 7         int result = arithmeticCalculator.add(11, 12);
 8         System.out.println("result:" + result);
 9         result = arithmeticCalculator.div(21, 3);
10         System.out.println("result:" + result);
11         */
12 
13         //AOP实现添加日志功能
14         ApplicationContext ctx = new ClassPathXmlApplicationContext("com/aop/beans/beans-aop.xml");
15         ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
16         
17         System.out.println(arithmeticCalculator.getClass().getName());
18         
19         int result = arithmeticCalculator.add(11, 12);
20         System.out.println("result:" + result);
21         result = arithmeticCalculator.div(21, 2);
22         System.out.println("result:" + result);
23         
24     }
25     
26 }
测试类
原文地址:https://www.cnblogs.com/wwzyy/p/5151471.html