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类进行干预,两个切面类是谁先干预?

相关推荐
喵手1 分钟前
反射机制:你真的了解它的“能力”吗?
java·后端·java ee
用户466537015052 分钟前
git代码压缩合并
后端·github
武大打工仔6 分钟前
从零开始手搓一个MVC框架
后端
开心猴爷11 分钟前
移动端网页调试实战 Cookie 丢失问题的排查与优化
后端
kaika111 分钟前
告别复杂配置!使用 1Panel 运行环境功能轻松搭建 Java 应用
java·1panel·建站·halo
用户57240561411 分钟前
解析Json
后端
舒一笑12 分钟前
Mac 上安装并使用 frpc(FRP 内网穿透客户端)指南
后端·网络协议·程序员
每天学习一丢丢18 分钟前
Spring Boot + Vue 项目用宝塔面板部署指南
vue.js·spring boot·后端
邹小邹18 分钟前
Go 1.25 强势来袭:GC 速度飙升、并发测试神器上线,内存检测更精准!
后端·go
有梦想的攻城狮19 分钟前
Java 11中的Collections类详解
java·windows·python·java11·collections