在上篇文章中学习了Spring AOP,并学习了前置通知和后置通知。地址为:http://www.cnblogs.com/dreamfree/p/4095858.html
在本文中,将继续上篇的学习,继续了解返回通知、异常通知和环绕通知。具体的含义详见代码注释
1 package com.yl.spring.aop;
2
3 import java.util.Arrays;
4
5 import org.aspectj.lang.JoinPoint;
6 import org.aspectj.lang.ProceedingJoinPoint;
7 import org.aspectj.lang.annotation.After;
8 import org.aspectj.lang.annotation.AfterReturning;
9 import org.aspectj.lang.annotation.AfterThrowing;
10 import org.aspectj.lang.annotation.Around;
11 import org.aspectj.lang.annotation.Aspect;
12 import org.aspectj.lang.annotation.Before;
13 import org.springframework.stereotype.Component;
14
15 @Component
16 @Aspect
17 public class LoggingAspect {
18
19 /**
20 * 在com.yl.spring.aop.ArithmeticCalculator接口的每一个实现类的每一个方法开始之前执行一段代码
21 */
22 @Before("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
23 public void beforeMethod(JoinPoint joinPoint) {
24 String methodName = joinPoint.getSignature().getName();
25 Object[] args = joinPoint.getArgs();
26 System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
27 }
28
29 /**
30 * 在com.yl.spring.aop.ArithmeticCalculator接口的每一个实现类的每一个方法执行之后执行一段代码
31 * 无论该方法是否出现异常
32 */
33 @After("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
34 public void afterMethod(JoinPoint joinPoint) {
35 String methodName = joinPoint.getSignature().getName();
36 Object[] args = joinPoint.getArgs();
37 System.out.println("The method " + methodName + " ends with " + Arrays.asList(args));
38 }
39
40 /**
41 * 方法正常结束后执行的代码
42 * 返回通知是可以访问到方法的返回值的
43 */
44 @AfterReturning(value="execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))", returning="result")
45 public void afterReturning(JoinPoint joinPoint, Object result) {
46 String methodName = joinPoint.getSignature().getName();
47 System.out.println("The method " + methodName + " return with " + result);
48 }
49
50 /**
51 * 在方法出现异常时会执行的代码
52 * 可以访问到异常对象,可以指定在出现特定异常时在执行通知代码
53 */
54 @AfterThrowing(value="execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))", throwing="ex")
55 public void afterThrowing(JoinPoint joinPoint, Exception ex) {
56 String methodName = joinPoint.getSignature().getName();
57 System.out.println("The method " + methodName + " occurs exception: " + ex);
58 }
59
60 /**
61 * 环绕通知需要携带ProceedingJoinPoint类型的参数
62 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
63 * 而且环绕通知必须有返回值,返回值即为目标方法的返回值
64 */
65 @Around("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
66 public Object aroundMethod(ProceedingJoinPoint pjd) {
67 Object result = null;
68 String methodName = pjd.getSignature().getName();
69 //执行目标方法
70 try {
71 //前置通知
72 System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
73 result = pjd.proceed();
74 //返回通知
75 System.out.println("The method " + methodName + " ends with " + Arrays.asList(pjd.getArgs()));
76 } catch (Throwable e) {
77 //异常通知
78 System.out.println("The method " + methodName + " occurs expection : " + e);
79 throw new RuntimeException(e);
80 }
81 //后置通知
82 System.out.println("The method " + methodName + " ends");
83 return result;
84 }
85
86 }
切面的优先级
为项目增加一个新的切面类,负责验证功能,则需要指定切面执行的顺序。即切面的优先级。具体方法是给切面类增加@Order注解,并指定具体的数字,值越小优先级越高
1 package com.yl.spring.aop;
2
3 import java.util.Arrays;
4
5 import org.aspectj.lang.JoinPoint;
6 import org.aspectj.lang.annotation.Aspect;
7 import org.aspectj.lang.annotation.Before;
8 import org.springframework.core.annotation.Order;
9 import org.springframework.stereotype.Component;
10
11 /**
12 * 可以使用@Order注解指定切面的优先级,值越小优先级越高
13 * @author yul
14 *
15 */
16 @Order(2)
17 @Component
18 @Aspect
19 public class ValidationAspect {
20
21 @Before("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
22 public void vlidateArgs(JoinPoint joinPoint) {
23 System.out.println("validate: " + Arrays.asList(joinPoint.getArgs()));
24 }
25 }
切点表达式的重用:
在LoggingAspect类中,切点的表达式可以先定义,在使用。
1 package com.yl.spring.aop;
2
3 import java.util.Arrays;
4
5 import org.aspectj.lang.JoinPoint;
6 import org.aspectj.lang.ProceedingJoinPoint;
7 import org.aspectj.lang.annotation.After;
8 import org.aspectj.lang.annotation.AfterReturning;
9 import org.aspectj.lang.annotation.AfterThrowing;
10 import org.aspectj.lang.annotation.Around;
11 import org.aspectj.lang.annotation.Aspect;
12 import org.aspectj.lang.annotation.Before;
13 import org.aspectj.lang.annotation.Pointcut;
14 import org.springframework.core.annotation.Order;
15 import org.springframework.stereotype.Component;
16 @Order(1)
17 @Component
18 @Aspect
19 public class LoggingAspect {
20
21 /**
22 * 定义一个方法,用于声明切入点表达式。一般的,该方法中再不需要添加其他的代码
23 * 使用@Pointcut 来声明切入点表达式
24 * 后面的其他通知直接使用方法名直接引用方法名即可
25 */
26 @Pointcut("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
27 public void declareJoinPointExpression() {
28
29 }
30
31 /**
32 * 在com.yl.spring.aop.ArithmeticCalculator接口的每一个实现类的每一个方法开始之前执行一段代码
33 */
34 @Before("declareJoinPointExpression()")
35 public void beforeMethod(JoinPoint joinPoint) {
36 String methodName = joinPoint.getSignature().getName();
37 Object[] args = joinPoint.getArgs();
38 System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
39 }
40
41 /**
42 * 在com.yl.spring.aop.ArithmeticCalculator接口的每一个实现类的每一个方法执行之后执行一段代码
43 * 无论该方法是否出现异常
44 */
45 @After("declareJoinPointExpression()")
46 public void afterMethod(JoinPoint joinPoint) {
47 String methodName = joinPoint.getSignature().getName();
48 Object[] args = joinPoint.getArgs();
49 System.out.println("The method " + methodName + " ends with " + Arrays.asList(args));
50 }
51
52 /**
53 * 方法正常结束后执行的代码
54 * 返回通知是可以访问到方法的返回值的
55 */
56 @AfterReturning(value="declareJoinPointExpression()", returning="result")
57 public void afterReturning(JoinPoint joinPoint, Object result) {
58 String methodName = joinPoint.getSignature().getName();
59 System.out.println("The method " + methodName + " return with " + result);
60 }
61
62 /**
63 * 在方法出现异常时会执行的代码
64 * 可以访问到异常对象,可以指定在出现特定异常时在执行通知代码
65 */
66 @AfterThrowing(value="declareJoinPointExpression()", throwing="ex")
67 public void afterThrowing(JoinPoint joinPoint, Exception ex) {
68 String methodName = joinPoint.getSignature().getName();
69 System.out.println("The method " + methodName + " occurs exception: " + ex);
70 }
71
72 /**
73 * 环绕通知需要携带ProceedingJoinPoint类型的参数
74 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
75 * 而且环绕通知必须有返回值,返回值即为目标方法的返回值
76 */
77 @Around("declareJoinPointExpression()")
78 public Object aroundMethod(ProceedingJoinPoint pjd) {
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 //返回通知
87 System.out.println("The method " + methodName + " ends with " + Arrays.asList(pjd.getArgs()));
88 } catch (Throwable e) {
89 //异常通知
90 System.out.println("The method " + methodName + " occurs expection : " + e);
91 throw new RuntimeException(e);
92 }
93 //后置通知
94 System.out.println("The method " + methodName + " ends");
95 return result;
96 }
97
98 }
当处于不同的类,甚至不同的包时,可以使用包名.类名.方法名
具体代码如下:
1 package com.yl.spring.aop;
2
3 import java.util.Arrays;
4
5 import org.aspectj.lang.JoinPoint;
6 import org.aspectj.lang.annotation.Aspect;
7 import org.aspectj.lang.annotation.Before;
8 import org.springframework.core.annotation.Order;
9 import org.springframework.stereotype.Component;
10
11 /**
12 * 可以使用@Order注解指定切面的优先级,值越小优先级越高
13 * @author yul
14 *
15 */
16 @Order(2)
17 @Component
18 @Aspect
19 public class ValidationAspect {
20
21 @Before("com.yl.spring.aop.LoggingAspect.declareJoinPointExpression()")
22 public void vlidateArgs(JoinPoint joinPoint) {
23 System.out.println("validate: " + Arrays.asList(joinPoint.getArgs()));
24 }
25 }
|