定义:看看就得了===================================
面向方面编程(AOP,Aspect-Oriented Programming) 是一种编程范式,旨在通过分离横切关注点来提高程序的模块化。横切关注点是指那些影响多个模块的功能,例如日志记录、安全检查、事务管理等。AOP 允许开发人员将这些横切关注点抽取到独立的模块(称为切面),从而使核心业务逻辑更加简洁和专注。
使用场景:========================================
简单概括就是在对原模块代码无侵入的同时做功能增强:以下是常见使用场景:
1.日志记录:可以记录某些模块的方法的调用信息,参数,返回值,执行时间等等,然后可以存到数据库,这样就可以监控这个方法
2.事务管理:实际上@Transactional就是这样实现的
3.安全检查:我要求使用某些模块时要验证用户的身份信息,我都可以指定对这些执行执行aop验证用户身份信息的逻辑
4.缓存管理:实际上@Cachaeble就是这样实现的
5.异常处理:如果想捕获某些模块中的异常并处理,就可以使用aop
说着说着感觉说的功能好像过滤器拦截器都能实现,看看区别:
-
AOP:
- 应用层次:方法级别。
- 优点:
- 适用于业务逻辑层的横切关注点,能够精细地控制方法的前后处理。
- 提供了强大的切面功能,可以独立于业务逻辑代码进行管理。
- 缺点:
- 需要学习和理解 AOP 的概念和机制。
- 对于全局性的请求和响应处理不如过滤器方便。
-
拦截器:
- 应用层次:框架级别,一般在处理 HTTP 请求的过程中拦截。
- 优点:
- 可以在处理器执行前、执行后以及请求完成后进行拦截。
- 能够访问和修改请求和响应对象,适用于控制器层的任务。
- 缺点:
- 粒度不如 AOP 细,无法精确到业务方法的前后。
- 主要用于控制器层,无法直接作用于业务逻辑层。
-
过滤器:
- 应用层次:Servlet 容器级别,主要在 HTTP 请求和响应处理的前后进行过滤。
- 优点:
- 适用于全局性的预处理和后处理。
- 对所有请求和响应生效,不局限于特定的控制器或方法。
- 缺点:
- 粒度较粗,无法精确到特定的方法级别。
- 不适合处理业务逻辑层的横切关注点。
使用方式:下面以记录方法执行时间为例==================
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.比如我们要记录UserService类中所有方法的执行时间(这里是我们要增强的业务)
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void addUser(String username) {
System.out.println("Adding user: " + username);
// 模拟方法执行时间
try {
Thread.sleep(200); // 睡眠 200 毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void deleteUser(String username) {
System.out.println("Deleting user: " + username);
// 模拟方法执行时间
try {
Thread.sleep(300); // 睡眠 300 毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.定义切面类
package com.example.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ExecutionTimeAspect {
//定义切入点表达式,也就是要拦截哪些方法对他们做增强
//这里是拦截service包下的所有类,这个粒度可以随意控制,大到所有的类,小到针对某一个方法
@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
//方法执行前先记录当前时间
long start = System.currentTimeMillis();
// 执行被拦截的方法
Object proceed = joinPoint.proceed();
//计算方法执行耗时
long executionTime = System.currentTimeMillis() - start;
//输出方法执行耗时信息
System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return proceed;
}
}
4.当我们的方法被调用时,就会被切面类捕获到
@Component
public class Test {
@Autowired
private UserService userService;
public void main(String[] args){
userService.addUser("John");
userService.deleteUser("John");
}
}
5.然后就会输出如下信息
Adding user: John
execution(void com.example.service.UserService.addUser(String)) executed in 200ms
Deleting user: John
execution(void com.example.service.UserService.deleteUser(String)) executed in 300ms
通知类型和切入点表达式==============================
这里做个小介绍,不详细说明,因为有点复杂
通知类型(Advice Types)
在 AOP 中,通知(Advice)是指在程序执行的某个切入点(Pointcut)上执行的代码。Spring AOP 提供了多种通知类型,以便在方法执行的不同阶段进行拦截和处理。主要的通知类型包括:
- @Before:在目标方法执行之前执行通知。
- @After:在目标方法执行之后执行通知(无论目标方法是否抛出异常)。
- @AfterReturning:在目标方法成功返回之后执行通知。
- @AfterThrowing:在目标方法抛出异常之后执行通知。
- @Around:环绕目标方法执行通知,通知可以控制目标方法是否执行。
切入点表达式(Pointcut Expressions)
切入点表达式用于匹配连接点(Join Points),以便确定哪些方法或代码块将被通知所拦截。Spring AOP 使用 AspectJ 切入点表达式语言来定义切入点表达式。
常见的切入点表达式
- execution:匹配方法执行。
- within:匹配特定类型内的方法执行。
- this:匹配代理对象的类型。
- target:匹配目标对象的类型。
- args:匹配方法参数。
- @annotation:匹配方法上指定的注解。