AOP 概述
AOP
是 Spring
框架的第二大核心(第一大是 IoC
)
什么是 AOP
Aspect Oriented Programming
(面向切面编程)
什么是面向切面编程呢?切面就是指某一类特定问题,所以 AOP
也可以理解为面向特定方法编程
什么是面向特定方法编程呢?比如前面说到的“登录校验”,就是一类特定问题
- 登录校验拦截器,就是对“登录校验”这类问题的统一处理
- 所以,拦截器也是
AOP
的一种应用
AOP
是一种思想,拦截器是 AOP
思想的一种实现,Spring
框架实现了这种思想,提供了拦截器技术的相关接口
简单来说:AOP
是一种思想,是对某一类事情的集中处理
什么是 Spring AOP
AOP
是一种思想,它的实现方法有很多,由 Spring AOP
,也有 AspectJ
、CGLIB
等
Spring AOP
只是其中的一种实现方式
拦截器作用的维度是 URL
(一次请求和响应),@ControllerAdvice
应用场景主要是全局异常处理(配合自定义异常效果更佳),数据绑定,数据预处理。AOP
作用的维度更加细致(可以根据包、类、方法名、参数等进行拦截),能够实现更加复杂的业务逻辑
举个例子:
我们现在有个项目,项目中开发了很多的业务功能
现在有一些业务的执行效率比较低,耗时较长,我们需要对接口进行优化
- 第一步就需要定位出执行耗时比较长的业务方,再针对该业务方法来进行优化
如何定位呢?我们就需要统计当前项目中每一个业务方法的执行耗时
- 可以在业务方法运行前和运行后,记录下方法的开始时间和结束时间,两者的差就是这个方法的耗时
这种方法是可以解决问题的,但一个项目中会包含很多的业务模块,每个业务模块又有很多接口,一个接口又包含了很多方法,如果我们要在每个业务方法中都记录方法的耗时,对于程序员而言,会增加很多的工作量
AOP
就可以做到在不改动这些原始方法的基础上,针对特定的方法进行功能的增氧
AOP
的作用:在程序运行期间在不断修改源代码的基础上对已有方法进行增强(无侵入性:解耦)
Spring AOP 快速入门
引入依赖
在 pom.xml
中添加配制
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
编写 AOP 程序
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class TimeAspect {
/**
* 记录方法耗时
*/
@Around("execution(* com.example.demo.controller.*.*(..))")
public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
// 记录方法执行开始时间
long begin = System.currentTimeMillis();
// 执行原始方法
Object result = pjp.proceed();
// 记录方法执行结束时间
long end = System.currentTimeMillis();
// 记录方法执行耗时
log.info(pjp.getSignature() + "执行耗时:{}ms", end - begin);
return result;
}
}
- 运行程序,观察日志:
对程序进行简单讲解:
@Aspect
:标识这是一个切面类@Around
:环绕通知,在目标方法的前后都会被执行。后面的表达式表是对哪些方法进行增强PeoceedingJoinPoint.proceed()
让原始方法执行
整个代码分为三个部分
我们通过 AOP
入门程序完成了业务接口执行耗时的统计。通过上面的代码,我们可以感受到 AOP
面向切面编程的一些优势:
- 代码无侵入:不修改原始的业务方法,就可以对原始的业务方法进行了功能的增强或者是功能的改变
- 减少了重复代码
- 提高了开发效率
- 维护方便
Spring AOP 详解
下面我们来详细学习 AOP
,主要是以下几部分
Spring AOP
中涉及的核心概念Spring AOP
通知类型- 多个
AOP
程序的执行顺序
Spring AOP 核心概念
1. 切点(Pointcut)
切点(Pointcut
),也称之为“切入点”
Pointcut
的作用就是提供一组规则(使用 AspectJ pointcut expression language
来描述),告诉程序对哪些方法来进行功能增强
- 上面的表达式
execution(* com.example.demo.controller.*.*(..))
就是切点表达式
2. 连接点(Join Point)
满足切点表达式规则的方法,就是连接点,也就是可以被 AOP
控制的方法
以入门程序举例,所有 com.example.demo.controller
路径下的方法,都是连接点
package com.example.demo.controller;
@RequestMapping("/book")
@RestController
public class BookController {
@RequestMapping("/addBook")
public Result addBook(BookInfo bookInfo) {
//...代码省略
}
@RequestMapping("/queryBookById")
public BookInfo queryBookById(Integer bookId) {
//...代码省略
}
@RequestMapping("/updateBook")
public Result updateBook(BookInfo bookInfo) {
//...代码省略
}
}
- 上述
BookController
中的方法都是连接点
切点和连接点的关系
- 连接点是满足切点表达式的元素
- 切点可以看做是保存了众多连接点的集合
比如:- 切点表达式:全校老师
- 连接点就是:张老师、李老师、王老师等各个老师
3. 通知(Advice)
通知就是具体要做的工作,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
比如上述程序中记录业务方法的耗时时间,就是通知
- 在
AOP
面向切面编程当中,我们把这部分重复的代码抽取出来单独定义,这部分代码就是通知的内容
4. 切面(Aspect)
切面(Aspect)=切点(Pointcut
)+通知(Advice
)
通过切面就能够描述当前 AOP
程序需要针对哪些方法,在什么时候执行什么样的操作
- 切面既包含了通知逻辑的定义,也包括了连接点的定义
- 切面所在的类,我们一般称为切面类(被
@Aspect
注解标识的类)