Spring Boot使用AOP

一、为什么需要面向切面编程?

面向对象编程(OOP)的好处是显而易见的,缺点也同样明显。当需要为多个不具有继承关系的对象添加一个公共的方法的时候,例如日志记录、性能监控等,如果采用面向对象编程的方法,需要在每个对象里面都添加相同的方法,这样就产生了较大的重复工作量和大量的重复代码,不利于维护。面向切面编程(AOP)是面向对象编程的补充,简单来说就是统一处理某一"切面"的问题的编程思想。如果使用AOP的方式进行日志的记录和处理,所有的日志代码都集中于一处,不需要再每个方法里面都去添加,极大减少了重复代码。

二、Spring AOP术语

通知(Advice)包含了需要用于多个应用对象的横切行为,就是定义了"什么时候"和"做什么"。

连接点(Join Point)是程序执行过程中能够应用通知的所有点。

切点(Poincut)是定义了在"什么地方"进行切入,哪些连接点会得到通知。显然,切点一定是连接点。

切面(Aspect)是通知和切点的结合。通知和切点共同定义了切面的全部内容------是什么,何时,何地完成功能。

引入(Introduction)允许我们向现有的类中添加新方法或者属性。

织入(Weaving)是把切面应用到目标对象并创建新的代理对象的过程,分为编译期织入、类加载期织入和运行期织入。

三、Spring Boot AOP实战
1、引入依赖
XML 复制代码
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
   <version>2.7.2</version>
</dependency>

不需要再添加aspectjweaver的依赖了,因为spring-boot-starter-aop包含了aspectjweaver

2、 编写用于拦截的bean

直接定义一个controller

java 复制代码
@RestController
public class AopController {

    @GetMapping("/hello")
    public ResultMap sayHello(){
        ResultMap resultMap = new ResultMap();
        resultMap.setCode(1);
        resultMap.setMessage("响应成功");
        resultMap.setData("Hello World!");

        return resultMap;
    }
}
3、 定义切面

Spring采用@Aspect注解对POJO进行标注,该注解表明该类不仅仅是一个POJO,还是一个切面。切面是切点和通知的结合,那么定义一个切面就需要编写切点和通知。在代码中,只需要添加@Aspect注解即可。

(1)定义切点

切点是通过@Pointcut注解和切点表达式定义的。由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且实际中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。如图是execution表达式的语法:

execution表示在方法执行的时候触发。以"*"开头,表明方法返回值类型为任意类型。然后是全限定的类名和方法名,"*"可以表示任意类和任意方法。对于方法参数列表,可以使用".."表示参数为任意类型。如果需要多个表达式,可以使用"&&"、"||""!"完成与、或、非的操作。

(2)定义通知

通知有五种类型,分别是:

前置通知(@Before):在目标方法调用之前调用通知

后置通知(@After):在目标方法完成之后调用通知

环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法

返回通知(@AfterReturning):在目标方法成功执行之后调用通知

异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知

java 复制代码
@Aspect
@Component
public class AopAdvice {
    @Pointcut("execution(* com.mq.rabbit.controller.*.*(..))")
    public void pointCut(){

    }

    @Before("pointCut()")
    public void beforeAdvice(){
        System.out.println("\t------前置通知------");
    }

    @After("pointCut()")
    public void afterAdvice(){
        System.out.println("\t------后置通知------");
    }

    @Around("pointCut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint)  {
        System.out.println("------环绕通知开始------");
        Object result = null;
        try {
            result = joinPoint.proceed(); //接收Controller的返回值
        }catch (Throwable t){
            t.printStackTrace();
        }
        System.out.println("------环绕通知结束------");
        return result; //将Controller方法的返回值返回
    }
}
4、启动测试

运行项目,在浏览器访问http://localhost:端口号/项目名/hello,控制台输出如图所示:

相关推荐
Daniel 大东10 分钟前
idea 解决缓存损坏问题
java·缓存·intellij-idea
2401_8576363911 分钟前
共享汽车管理新纪元:SpringBoot框架应用
数据库·spring boot·汽车
wind瑞17 分钟前
IntelliJ IDEA插件开发-代码补全插件入门开发
java·ide·intellij-idea
HappyAcmen17 分钟前
IDEA部署AI代写插件
java·人工智能·intellij-idea
马剑威(威哥爱编程)22 分钟前
读写锁分离设计模式详解
java·设计模式·java-ee
鸽鸽程序猿23 分钟前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
修道-032324 分钟前
【JAVA】二、设计模式之策略模式
java·设计模式·策略模式
九圣残炎29 分钟前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode
当归102442 分钟前
若依项目-结构解读
java
man201744 分钟前
【2024最新】基于springboot+vue的闲一品交易平台lw+ppt
vue.js·spring boot·后端