Spring AOP -- 10大细节之细节八:环绕通知

本文深入解析Spring AOP中的环绕通知机制,介绍其作为最强大的通知类型如何实现动态代理,并通过实例展示环绕通知如何整合前置、返回、异常和后置通知。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;

}


}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值