Spring AOP

光标放在要添加异常的那行,ALT+ENTER自动添加异常处理

目录

🍁添加依赖

🍁简单上手AOP

🍁执行效果

🍁AOP详解

🍀切点

🍀连接点

🍀通知

🍀切面

🍁通知类型

🍁@PointCut

🍁切面优先级

🍀同一类有多个@Before

🍀不同类有多个@Before

🍁切点表达式

🍁@annotation

🍀1.自定义注解

🍀2.切面类

🍀3.在目标方法上添加自定义注解


🍁添加依赖

XML 复制代码
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
   <version>3.5.10</version>
</dependency>

🍁简单上手AOP

1.@Aspect:标识着这是一个切面类,至于切面类是啥,先不讲,我先大概的介绍一下。

2.@Around:表示这个目标方法在前后都会被执行。记住,目标方法不是此注解修饰的方法。

3.pjp.proceed:执行目标方法。

4.pjp.getSignature:方法签名,如下图

5.throws Throwable异常处理:proceed方法要处理的异常,如下

🍁执行效果

所以有啥用呢,很明显,我们使用aop,能解耦,能在不改变原有方法的基础上,添加额外功能。而且还能减少我们写重复代码的成本,一定程度上提高了代码的可读性。

🍁AOP详解

🍀切点

前后两个红框框的就是切点。

我标红框框的后面那个就是切点表达式,

切点表达式:对哪个原方法进行代码增强。

切点:就是切点啊,名字是这么叫的哈哈。

🍀连接点

里面的com.example.bookslistdemo.controller路径下的所有类底下的所有方法都是连接点也就是要增强的方法嘛。

🍀通知

红框框的这部分代码逻辑就是通知。

🍀切面

包含切点和返回值的通知就是切面,也就是上图标红框框的就是切面。

🍁通知类型

一共5个通知

@Around:环绕通知,这个不用多讲。

@Before:前置通知,在目标方法前被执行。

@After:后置通知,在目标方法后被执行。

@AfterReturning:返回后通知,在目标方法后被执行,有异常不会执行!

@AfterThrowing:异常后通知,在目标方法在发生异常后执行!

我们用代码看一看他们的执行顺序,

java 复制代码
@Slf4j
@Aspect
@Component
public class TimeAspect {

    @Before("execution(* com.example.bookslistdemo.controller.*.*(..))")
    public void doBefore(){
        log.info("执行Before方法");
    }

    @After("execution(* com.example.bookslistdemo.controller.*.*(..))")
    public void doAfter(){
        log.info("执行After方法");
    }

    @AfterReturning("execution(* com.example.bookslistdemo.controller.*.*(..))")
    public void doAfterReturning(){
        log.info("执行AfterReturning方法");
    }

    @AfterThrowing("execution(* com.example.bookslistdemo.controller.*.*(..))")
    public void doAfterThrowing(){
        log.info("执行AfterThrowing方法");
    }


    @Around("execution(* com.example.bookslistdemo.controller.*.*(..))")
    public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {

        log.info("Around 方法开始执行");
        Object result=pjp.proceed();
        log.info("Around 方法结束执行");

        return result;

    }
}

然后访问user/login方法,

执行结果发现,

然后我们发现其实,好像只有@Around注解有返回值Object和参数ProceedingJoinPoint pjp吧,其它的都是清一色的void返回值,并且没有参数!

🍁@PointCut

上面我们写的那种写法,还得每个注解后面加上那么一长串路径,看着就头疼,所以我们可以借助@PointCut注解来简化我们的代码

具体如下

java 复制代码
    @Pointcut("execution(* com.example.bookslistdemo.controller.*.*(..))")
    private void pt(){}

    @Before("pt()")
    public void doBefore(){
        log.info("执行Before方法");
    }

@PointCut注解后跟切点表达式,来定义路径。

此后,如果需要用到这个路径,就在注解后面加上@PointCut注解修饰的方法名即可。

这样就极大的简化了我们的代码,也提高了代码可读性。

🍁切面优先级

🍀同一类有多个@Before

java 复制代码
package com.example.bookslistdemo.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class TimeAspect {
    @Pointcut("execution(* com.example.bookslistdemo.controller.*.*(..))")
    private void pt(){}

    @Before("pt()")
    public void doBefore4(){
        log.info("执行Before4方法");
    }

    @Before("pt()")
    public void doBefore2(){
        log.info("执行Before2方法");
    }

    @Before("pt()")
    public void doBefore3(){
        log.info("执行Before3方法");
    }

    @After("pt()")
    public void doAfter(){
        log.info("执行After方法");
    }

    @AfterReturning("pt()")
    public void doAfterReturning(){
        log.info("执行AfterReturning方法");
    }

    @AfterThrowing("pt()")
    public void doAfterThrowing(){
        log.info("执行AfterThrowing方法");
    }


    @Around("pt()")
    public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {

        log.info("Around 方法开始执行");
        Object result=pjp.proceed();
        log.info("Around 方法结束执行");

        return result;

    }
}

访问后执行

发现我们的代码其实是按doBefore4--doBefore2--doBefore3的顺序方法名来的,但是执行是按

2--3--4来的,大家注意一下这种情况好吧。我只是给大家演示一下。

🍀不同类有多个@Before

类1

类2

类3

访问后观察

很明显它就是按数字的顺序来执行的,但我想说的是,它也按字母abcd的先执行!!

总结:@Before注解字母越小越先执行

@After注解字母越大越先执行

然后加上@Order注解试试

结果:

发现@Order里数字越小的,@Before越先执行

@Order里数字越大的@After越先执行!!

🍁切点表达式

第一个*表示返回类型,后面两个*都是表示一个占位,大家应该清楚,类.方法,最后面的那个(. .)表示无参和有参都行,且无论参数个数。

java 复制代码
("execution(* com.example.bookslistdemo.controller.*.*(..))")

那如果我改一下

java 复制代码
("execution(* com.example.bookslistdemo.controller..*(..))")

呢,表示controller下的所有子孙都匹配。

具体就这么些。

🍁@annotation

🍀1.自定义注解

复制代码
@Target(ElementType.METHOD)表示修饰的是方法,
复制代码
@Retention(RetentionPolicy.RUNTIME)表示是运行时存在。

🍀2.切面类

🍀3.在目标方法上添加自定义注解

执行结果

所以咋们一个自定义注解想加到哪个方法上哪个方法就生效,是不是很香。

但我们还可以在切面类里面改成下面这样--用@PointCut注解

结果也是一样的。

本篇博客完结,啦。

相关推荐
万邦科技Lafite1 小时前
京东item_get接口实战案例:实时商品价格监控全流程解析
java·开发语言·数据库·python·开放api·淘宝开放平台
Mr_pyx2 小时前
Spring AI 入门教程:Java开发者的AI应用捷径
java·人工智能·spring
Zephyr_03 小时前
Leedcode算法题
java·算法
苍煜3 小时前
Java开发IO零基础吃透:BIO、NIO、同步异步、阻塞非阻塞
java·python·nio
折哥的程序人生 · 物流技术专研4 小时前
Java面试85题图解版(一):基础核心篇
java·开发语言·后端·面试
AllData公司负责人4 小时前
通过Postgresql同步到Doris,全视角演示AllData数据中台核心功能效果,涵盖:数据入湖仓,数据同步,数据处理,数据服务,BI可视化驾驶舱
java·大数据·数据库·数据仓库·人工智能·python·postgresql
Hello.Reader4 小时前
算法基础(十)——分治思想把大问题拆成小问题
java·开发语言·算法
一只大袋鼠4 小时前
JavaWeb四种文件上传方式(下篇)
java·开发语言·springmvc·javaweb
TE-茶叶蛋5 小时前
深入研究 yudao-framework 模块:Java 编程能力提升指南
java·开发语言