Spring-AOP

切面类:有方法开始、方法返回、方法异常、方法结束。(通知方法)

~切入点: 执行通知方法的叫切入点,通过切入点表达式------>选择有需要的切入点。

作用:切面类定义的通知方法动态发现目标对象执行哪个位置,动态插入目标对象中。

编写通知方法,告诉spring一下通知方法何时何地运行(切入点表达式)。

~连接点:封装了当前目标对象详细信息,在参数使用JoinPoint。

切入点

一、何时?

@Before方法执行之前运行

@AfterReturning方法执行正常返回结果运行

@AfterThrowing方法抛出异常运行

@After方法执行之后运行

@Around环绕通知

二、何地?

切入点表达式:

1)execution(方法的全签名)

1.全写法:public int com.scoro.spring.aop.calculator.MathCalculator.add(int,int)

2.省略写法:int add(int ,int)

通配符:

..; ①任意多个参数和类型(参数位置)②代表多个层级(类型位置)

*;代表所有(任意字符)

2)args(int,int)------>以指定参数切入

3)@annotation("注解全类名")------>标了注解的切(方法上有没有标注解)

java 复制代码
@Component
public class MathCalculatorImpl implements MathCalculator {
    @Override
    public int add(int a, int b) {
        int sun=a+b;
        System.out.println("sum="+sun);
        return sun;
    }
    @Override
    public int subtract(int a, int b) {
        int sun=a-b;
        System.out.println("sum="+sun);
        return sun;
    }
    @Override
    public int multiply(int a, int b) {
        int sun=a*b;
        System.out.println("sum="+sun);
        return sun;
    }
    @Override
    public int divide(int a, int b) {
        int sun=a/b;
        System.out.println("sum="+sun);
        return sun;
    }

    @MyAn
    @Override
    public void annMethod(int a, int b) {
        System.out.println("annotation"+a);
    }
}
java 复制代码
@Component
@Aspect //告诉spring这个组件是切面
public class LogAspect {
//    方法执行之前运行
    @Before("execution(int com.scoro.spring.aop.calculator.MathCalculator.*(..))")
    public void logBefore() {
        System.out.println("切面~开始");
    }

//    方法执行正常返回结果运行
    @AfterReturning("execution(int *(int,int))")
    public void logReturn() {
        System.out.println("切面~返回");
    }

//    方法抛出异常运行
    @AfterThrowing("execution(int *(int,int))")
    public void logException() {
        System.out.println("切面~异常");
    }

//    方法执行之后运行
    @After("execution(int *(int,int))")
    public void logAfter() {
        System.out.println("切面~结束");
    }

    @Before("args(int,int)")  //args:以指定参数切
    public void arg(){
        System.out.println("切面~parameter");
    }

    @Before("@annotation(com.scoro.spring.aop.annotation.MyAn)")  //@annotation注解:标了注解的切(方法上有没有标注解)
    public void annoMethod(){
        System.out.println("切面~annotation");
    }
}
java 复制代码
@Target({ ElementType.PARAMETER,ElementType.METHOD}) //说明注解的作用目标,里面value值按需求添加
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAn {

}

@Pointcut 简化开发

java 复制代码
@Component
@Aspect //告诉spring这个组件是切面
public class LogAspect {

    @Pointcut("execution(int com.scoro.spring.aop.calculator.MathCalculator.*(..))")
    public void pointCut(){} //空方法是为了给被人引用

    @Before("pointCut()")
    public void logBefore() {
        System.out.println("切面~开始");
    }

    @AfterReturning(value = "pointCut()")
    public void logReturn() {
        System.out.println("切面~返回");
    }
}

@Around环绕通知

环绕通知:①整合了前面四种通知方法

②可以控制目标方法是否执行,修改目标方法参数等执行结果。

java 复制代码
@Aspect
@Component
public class AroundAspect {
    @Pointcut("execution(int com.scoro.spring.aop.calculator.MathCalculator.*(..))")
    public void pointCut(){}
    /**
     * 环绕通知固定写法:
     * Object:返回值
     * ProceedingJoinPoint:可以继续推进的切点
     */

    @Around("pointCut()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
//        获取目标参数
        Object[] args = proceedingJoinPoint.getArgs();
//        前置
        System.out.println("环绕~前置");
        Object proceed=null;
        try {
            //    接受传参数的proceed,在传参数前实现修改目标方法执行用的参数
            args[1]=9;  //修改参数
            proceed = proceedingJoinPoint.proceed(args);//继续执行目标方法
            System.out.println("环绕~返回"+proceed);
        }catch (Exception e){
            System.out.println("环绕~异常");
            throw e; //吃掉异常,抛出异常
        }finally {
            System.out.println("环绕~后置");
        }
//        修改返回值
        return proceed;
    }
}

连接点

JoinPoint 连接点:获取当前目标方法的详细信息

java 复制代码
@Component
@Aspect
public class LogAspect {
    @Before("execution(int com.scoro.spring.aop.calculator.MathCalculator.*(..))")
    public void logBefore(JoinPoint joinPoint) {
 //       拿到方法全签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//        方法名
        String name = signature.getName();
//        目标方法传过来的参数值
        Object[] args = joinPoint.getArgs();
        System.out.println(name+"切面~开始"+ Arrays.toString(args));
    }

    @AfterReturning(value = "execution(int *(int,int))",returning = "result") //returning = "result"获取目标方法返回值
    public void logReturn(JoinPoint joinPoint,Object result) {
 //      获取目标方法返回值
        System.out.println("切面~返回"+result);
    }

    @AfterThrowing(value = "execution(int *(int,int))",throwing = "e")
    public void logException(JoinPoint joinPoint,Exception e) {
        System.out.println("切面~异常"+e);
    }
}

多切面执行顺序

例:有两个切面对MathCalculatorImpl类进行干预,两个切面类是谁先干预?

相关推荐
程序猿DD2 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
蛋蛋的就会顺顺的5 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
余槐i5 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8265 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡5 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
凤山老林6 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne7 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF8 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
silvamux_8 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
pride.li8 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉