8、环绕通知
1、环绕通知是Spring中最强大的通知,环绕通知其实就是一个动态代理
2、手写版的动态代理:
* try{
* @Before //前置通知
* method.invoke(obj,args);
* @AfterReturning //返回通知
* }
* catch(Exception e){
* @AfterThrowing //异常通知
*
* }
* finally{
* @After //后置通知
*环绕通知中有一个参数:ProceedingJoinPoint
* }
这四个通知四合一就是环绕通知
3、环绕通知方法源码:
@Around("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public Object myAround(ProceedingJoinPoint pjp) {
//拿到参数
Object[] args = pjp.getArgs();
Signature signature = pjp.getSignature();
String name = signature.getName();
Object proceed = null;
try {
//环绕的前置通知
System.out.println("环绕的前置通知...."+name+"方法执行了....他的参数是:"+Arrays.asList(args));
//就是利用反射调用目标方法执行,跟method.invoke是一样的
proceed = pjp.proceed(args);
//环绕的返回通知
System.out.println("环绕的返回通知....."+name+"方法正常执行,值为:"+proceed);
} catch (Throwable e) {
//环绕的异常通知
System.out.println("环绕的异常通知...."+name+"方法出现了异常,异常信息是:"+e);
} finally {
//环绕的后置通知
System.out.println("环绕的后置通知....."+name+"方法结束了");
}
//反射调用后的返回值,相当于method.invoke返回的result
return proceed;
}
4、解释:
proceed = pjp.proceed(args)
这条语句其实就是method.invoke,以前手写版的动态代理,也是method.invoke执行了,jdk才会利用反射进行动态代理的操作,在spring的环绕通知里面,只有这条语句执行了,spring才会去切入到目标方法中。
为什么说环绕通知就是一个动态代理呢?
首先,proceed = pjp.proceed(args)这条语句就是动态代理的开始,当我们把这条语句用try-catch包围起来的时候,在这条语句前面写的信息,就相当于前置通知,在它后面写的就相当于返回通知,在catch里面写的就相当于异常通知,在finally里写的就相当于后置通知。
源码:Logutils:
将其他的注解先注释掉,以免影响环绕通知的效果
package com.fxp.util;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
public class LogUtils {
//@Pointcut("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public void method(){
}
// @Before("method()")
public static void logStart(JoinPoint joinPoint){
//拿到目标方法的参数
Object[] args = joinPoint.getArgs();
//拿到目标方法的方法签名
Signature signature = joinPoint.getSignature();
//获取方法名
String name = signature.getName();
System.out.println("["+name+"]开始执行.....它的参数是:"+Arrays.asList(args)+"");
}
// @AfterReturning(value="method()",returning = "result")
public static void LogReturn(JoinPoint joinPoint,Object result){
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println("["+name+"]正常执行完毕.....,结果是:"+result+"");
}
//@AfterThrowing(value="method()",throwing = "e")
public static void LogErr(JoinPoint joinPoint,Exception e) {
Signature signature = joinPoint.getSignature();
String name = signature.getName();
//拿到异常信息
System.out.println("["+name+"]出现异常:"+e+"");
}
//@After("method()")
public static void LogEnd(JoinPoint joinPoint) {
System.out.println("["+joinPoint.getSignature().getName()+"]方法最终执行完毕");
}
/**
* 细节八
* 环绕通知是Spring中最强大的通知
* 环绕通知其实就是一个动态代理
* 手写版的动态代理:
* try{
* @Before //前置通知
* method.invoke(obj,args);
* @AfterReturning //返回通知
* }
* catch(Exception e){
* @AfterThrowing //异常通知
*
* }
* finally{
* @After //后置通知
* }
* 这四个通知四合一就是环绕通知
* 环绕通知中有一个参数:ProceedingJoinPoint
*
*/
@Around("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public Object myAround(ProceedingJoinPoint pjp) {
//拿到参数
Object[] args = pjp.getArgs();
Signature signature = pjp.getSignature();
String name = signature.getName();
Object proceed = null;
try {
//环绕的前置通知
System.out.println("环绕的前置通知...."+name+"方法执行了....他的参数是:"+Arrays.asList(args));
//就是利用反射调用目标方法执行,跟method.invoke是一样的
proceed = pjp.proceed(args);
//环绕的返回通知
System.out.println("环绕的返回通知....."+name+"方法正常执行,值为:"+proceed);
} catch (Throwable e) {
//环绕的异常通知
System.out.println("环绕的异常通知...."+name+"方法出现了异常,异常信息是:"+e);
} finally {
//环绕的后置通知
System.out.println("环绕的后置通知....."+name+"方法结束了");
}
//反射调用后的返回值,相当于method.invoke返回的result
return proceed;
}
}
运行结果: