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

1 public interface ArithmeticCalculator {
2
3     int add(int i, int j);
4     int sub(int i, int j);
5
6     int mul(int i, int j);
7     int div(int i, int j);
8
9 }

接口,要求为每个方法前后添加日志

 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 }

方法三:利用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 }

测试类

时间: 2024-08-06 03:21:07

Spring AOP 5种通知与java动态代理的相关文章

Spring AOP中的JDK和CGLib动态代理哪个效率更高?

一.背景 今天有小伙伴面试的时候被问到:Spring AOP中JDK 和 CGLib动态代理哪个效率更高? 二.基本概念 首先,我们知道Spring AOP的底层实现有两种方式:一种是JDK动态代理,另一种是CGLib的方式. 自Java 1.3以后,Java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,后来这项技术被用到了Spring的很多地方. JDK动态代理主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler.其中,Invoc

Spring AOP的底层实现技术---JDK动态代理

JDK动态代理    在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在我们终于发现动态代理是实现AOP的绝好底层技术.    JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler.其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起.   而

Java动态代理 深度详解

代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理模式从类型上来说,可以分为静态代理和动态代理两种类型. 今天我将用非常简单易懂的例子向大家介绍动态代理的两种类型,接着重点介绍动态代理的两种实现方式(Java 动态代理和 CGLib 动态代理),最后深入剖析这两种实现方式的异同,最后说说动态代理在我们周边框架中的应用. 在开始之前,我们先假设这样一个场景:有一个蛋糕店,它们都是使用蛋糕机来做蛋糕的,而且不同种类的蛋糕

Java 动态代理机制分析及扩展,第 1 部分

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 回页首 代理:设计模式 代理是一种常用的设计

Java 动态代理机制分析及扩展

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架.通过阅读本文,读者将会对 Java 动态代理机制有更加深入的理解.本文首先从 Java 动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现. 代理:设计模式 代理是一种常用的设计模式,其

java动态代理简述

代理模式 一个典型的动态代理创建对象过程可分为以下四个步骤:1.通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);2.通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});3.通过反射机制获取动态代理类的构

Java动态代理--&gt;Spring AOP

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.): [1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081 [2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123293 [3] 属性

java动态代理,及spring AOP

介绍:spring 的AOP (Aspect Oriented Programming)是通过java的动态代理来实现的,对于AOP不了解的朋友可以去网上看相关资料,我这里重点说明实现原理即java动态代理 要谈java动态代理就不得不说java的代理模式,我这里只给出代理模式的UML图 如图(1)及动态代理模式的UML类图 如图(2) 说明:图(2)中的红色红色斜体的类或接口是由java类库提供的即 Proxy和InvocationHandler 是java对动态代理的支持 图 (1) 和 图

Java动态代理学习【Spring AOP基础之一】

Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.lang.reflect.Proxy 首先从代码层面说明Java动态代理是如何实现的, 业务逻辑接口: /** * 创建一个人的接口,其中有一个吃的方法 */ public interface Person { public void eat(); } 创建一个实现该业务接口的类: /** * 人接口的