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

相关推荐
JohnYan10 分钟前
Bun技术评估 - 03 HTTP Server
javascript·后端·bun
周末程序猿18 分钟前
Linux高性能网络编程十谈|C++11实现22种高并发模型
后端·面试
ZHOU_WUYI25 分钟前
Flask与Celery 项目应用(shared_task使用)
后端·python·flask
忠于明白25 分钟前
Spring AI 核心工作流
人工智能·spring·大模型应用开发·spring ai·ai 应用商业化
陈小桔29 分钟前
限流算法java实现
java
黑客老李33 分钟前
JavaSec | SpringAOP 链学习分析
java·运维·服务器·开发语言·学习·apache·memcached
勤奋的知更鸟1 小时前
Java编程之原型模式
java·开发语言·原型模式
冒泡的肥皂1 小时前
强大的ANTLR4语法解析器入门demo
后端·搜索引擎·编程语言
叶 落1 小时前
[Java 基础]数组
java·java 基础
KK溜了溜了1 小时前
JAVA-springboot log日志
java·spring boot·logback