版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011171125/article/details/85849715
返回通知
使用`@AfterReturning`注解,在方法正常结束后执行的通知,它是可以获得方法的返回值的。
- 在
LoggingAspect
类中添加如下方法:
使用/** * 在方法正常结束后执行的代码 * 返回通知是可以访问到方法的返回值的 * @param joinPoint */ @AfterReturning(value="execution(* *.*(..))",returning="result") public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " ends with "+result); }
@AfterReturning
注解,注解中的returning
获取返回值。
测试结果:com.sun.proxy.$Proxy10 The methodadd begins...[3, 6] The method add ends... The method add ends with 9 result:9 The methoddiv begins...[6, 3] The method div ends... The method div ends with 2 result:2
异常通知
使用`@AfterThrowing`注解,在目标方法出现异常时会执行的代码,可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码
- 在
LoggingAspect
类中添加afterThrowing
方法:/** * 在目标方法出现异常时会执行的代码 * 可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码 * @param joinPoint * @param ex */ @AfterThrowing(value="execution(* *.*(..))",throwing="ex") public void afterThrowing(JoinPoint joinPoint, Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " occurs exception: "+ex); }
- 测试:
测试方法:
测试结果:public class Main { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml"); ArithmeticCalculator arithmeticCalculator = ctx.getBean(ArithmeticCalculator.class); System.out.println(arithmeticCalculator.getClass().getName()); int result = arithmeticCalculator.add(3, 6); System.out.println("result:" + result); result = arithmeticCalculator.div(6, 3); System.out.println("result:" + result); result = arithmeticCalculator.div(6, 0); System.out.println("result:" + result); } }
com.sun.proxy.$Proxy11 The methodadd begins...[3, 6] The method add ends... The method add ends with 9 result:9 The methoddiv begins...[6, 3] The method div ends... The method div ends with 2 result:2 The methoddiv begins...[6, 0] The method div ends... The method div occurs exception: java.lang.ArithmeticException: / by zero Exception in thread "main" java.lang.ArithmeticException: / by zero at com.fafa.spring.aop.impl.ArithmeticCalculatorImpl.div(ArithmeticCalculatorImpl.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) at com.sun.proxy.$Proxy11.div(Unknown Source) at com.fafa.spring.aop.impl.Main.main(Main.java:19)
环绕通知
- 使用
@Around
注解; - 环绕通知需要携带ProceedingJoinPoint类型的参数;
- 环绕通知类似于动态代理的全过程:ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法;
- 且环绕通知必须有返回值,返回值即为有目标方法的返回值。
- 注释掉
LoggingAspect
类中的其它的方法,添加如下方法:/** * 环绕通知需要携带ProceedingJoinPoint类型的参数。 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法。 * 且环绕通知必须有返回值,返回值即为有目标方法的返回值 * @param proceedingJoinPoint */ @Around(value="execution(* *.*(..))") public Object aroundMethd(ProceedingJoinPoint pjd){ String methodName = pjd.getSignature().getName(); Object result = null; try { // 前置通知 System.out.println("The method "+methodName+ " begins"); result = pjd.proceed(); // 返回通知 System.out.println("The method "+methodName+" ends with "+result); } catch (Throwable e) { // 异常通知 System.out.println("The method "+methodName+ " occurs exception: "+e); e.printStackTrace(); } // 后置通知 System.out.println("The method "+methodName+ " ends "); return result; }
- 测试(去掉除0的):
可见环绕通知和动态代理是非常类似的,可以控制到方法是否执行,方法的返回值。com.sun.proxy.$Proxy8 The method add begins The method add ends with 9 The method add ends result:9 The method div begins The method div ends with 2 The method div ends result:2
切面的优先级
- 此时我们再定义一个切面类
ValidationAspect
:@Component @Aspect public class ValidationAspect { @Before("execution(public int com.fafa.spring.aop.impl.ArithmeticCalculator.*(int,int))") public void validateArgs(JoinPoint joinPoint){ System.out.println("-->validate:"+Arrays.asList(joinPoint.getArgs())); } }
- 注释掉
LoggingAspect
类中的aroundMethd
方法 - 执行main方法:
从结果看两个切面类中com.sun.proxy.$Proxy10 The methodadd begins...[3, 6] -->validate:[3, 6] The method add ends... The method add ends with 9 result:9 The methoddiv begins...[6, 3] -->validate:[6, 3] The method div ends... The method div ends with 2 result:2
@Before
都执行了,但是我们如果要控制它们的顺序该怎么办; - 此时可以在切面类上使用
@Order
注解指定切面的优先级,值越小优先级越高:@Component @Aspect @Order(1) public class ValidationAspect { @Before("execution(public int com.fafa.spring.aop.impl.ArithmeticCalculator.*(int,int))") public void validateArgs(JoinPoint joinPoint){ System.out.println("-->validate:"+Arrays.asList(joinPoint.getArgs())); } } // 把这个类声明为一个切面: 需要把该类放入到IOC容器中,再声明为一个切面 @Component @Aspect @Order(2) //使用Order指定切面的优先级,值越小优先级越高 public class LoggingAspect { // 声明该方法是一个前置通知:在目标方法开始之前执行 // @Before("execution(public int com.fafa.spring.aop.impl.ArithmeticCalculator.add(int, int))") @Before("execution(* com.fafa.spring.aop.impl.*.*(int, int))") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("The method" + methodName +" begins..." + args); } // 后置通知就是在目标方法执行后(无论是否发生异常),都会执行的通知 // 在后置通知中还不能访问目标方法执行的结果。 @After("execution(* com.fafa.spring.aop.impl.*.*(..))") public void afterMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+methodName+" ends..."); } /** * 在方法正常结束后执行的代码 * 返回通知是可以访问到方法的返回值的 * @param joinPoint */ @AfterReturning(value="execution(* *.*(..))",returning="result") public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " ends with "+result); } /** * 在目标方法出现异常时会执行的代码 * 可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码 * @param joinPoint * @param ex */ @AfterThrowing(value="execution(* *.*(..))",throwing="ex") public void afterThrowing(JoinPoint joinPoint, Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " occurs exception: "+ex); } /** * 环绕通知需要携带ProceedingJoinPoint类型的参数。 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法。 * 且环绕通知必须有返回值,返回值即为有目标方法的返回值 * @param proceedingJoinPoint */ /*@Around(value="execution(* *.*(..))") public Object aroundMethd(ProceedingJoinPoint pjd){ String methodName = pjd.getSignature().getName(); Object result = null; try { // 前置通知 System.out.println("The method "+methodName+ " begins"); result = pjd.proceed(); // 返回通知 System.out.println("The method "+methodName+" ends with "+result); } catch (Throwable e) { // 异常通知 System.out.println("The method "+methodName+ " occurs exception: "+e); e.printStackTrace(); } // 后置通知 System.out.println("The method "+methodName+ " ends "); return result; }*/ }
- 执行测试结果返回如下:
com.sun.proxy.$Proxy11 -->validate:[3, 6] The methodadd begins...[3, 6] The method add ends... The method add ends with 9 result:9 -->validate:[6, 3] The methoddiv begins...[6, 3] The method div ends... The method div ends with 2 result:2