AOP理念:
SpringAOP是一种是SpringFramwork中的一个重要组成部分,主要用于实现需要跨越多个对象来实现一些系统功能,常见的运用场景有:
缓存查询(在执行的时候先到缓存中查询,查询不到再执行数据库查询方法)
性能监控(可以在某个方法执行的前后计算运行时间)
事务管理(Spring内置了一个事务管理的切面,这个切面通过@Transactional注解来找到切点并实现事务开始,提交,回滚)
SpringBoot中基于注解使用AOP切面:
定义切面:
@Aspect
@Component
public class MyService {
@Pointcut("execution(void com.aop.demo.service.Target.helloAround())")
public void helloAround() {}
@Before("execution(void com.aop.demo.service.Target.helloBefore())")
public void before() {
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
}
@After("execution(void com.aop.demo.service.Target.helloAfter())")
public void after() {
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
}
@Around("helloAround()")
public void doSomething(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
pjp.proceed();
System.out.println("MyService叠加Buffer");
System.out.println("MyService叠加Buffer");
}
}
通知方式:
通知用于控制通知类的通知方法作用于切点也就是待增强方法的执行位置,具体含义如下:
前置通知(Before Advice)
- 定义:在方法调用之前执行。
- 用途:通常用于执行一些初始化工作,比如打开资源、设置事务等。
- 示例注解:
@Before
。后置通知(After Advice)
- 定义:无论方法是否成功执行,都会在方法调用之后执行。
- 用途:通常用于释放资源、关闭连接等。
- 示例注解:
@After
。返回后通知(After Returning Advice)
- 定义:仅在方法成功执行并返回结果之后执行。
- 用途:通常用于记录返回值或清理工作。
- 示例注解:
@AfterReturning
。抛出异常后通知(After Throwing Advice)
- 定义:仅在方法抛出异常后执行。
- 用途:通常用于记录异常或进行异常处理。
- 示例注解:
@AfterThrowing
。环绕通知(Around Advice)
- 定义:在方法调用前后都可以执行,甚至可以完全替代方法的执行。
- 用途:通常用于实现性能监控、事务控制等。
- 示例注解:
@Around
。
切点表达式:
切点表达式是描述切点的一种方式,它允许我们精确地指定哪些连接点应该被一个切面所影响。Spring AOP 使用 AspectJ 的切点表达式语法,这种语法非常灵活,能够让我们根据多种条件来选择连接点。
用法:
- execution():匹配特定签名的方法调用
execution(* com.example.service.*.*(..))
这个切点表达式会匹配 com.example.service
包下所有类的所有方法。
- this():匹配代理对象自身。
this(com.example.service.MyService)
这个切点表达式会匹配当代理对象是 MyService
实例时的方法调用。
- target():匹配目标对象。
target(com.example.service.MyService)
这个切点表达式会匹配当目标对象是 MyService
实例时的方法调用。
- args():匹配参数。
args(java.lang.String, ..)
这个切点表达式会匹配至少包含一个 String
类型参数的方法调用。
ps:为了加深记忆可以clone这个仓库的代码执行一下整个流程:Grobob101/Spring-AOP-Tutorial: 一个用于快速上手SpringAop的项目 (github.com)
SpringAOP执行流程
首先,创建一个切面,切面包含切点定义和通知(Advice)。切点定义了在哪些连接点(Join Points)上应用通知,而通知则是在这些连接点上执行的具体操作。Spring AOP或AspectJ通过切点来确定需要代理的目标类的方法。Spring AOP主要使用两种代理方式:JDK动态代理(用于接口)和CGLIB代理(用于类)。在创建代理对象时,根据切点和通知类型决定在目标方法的什么地方(如方法之前、之后或抛出异常时)执行通知逻辑,从而将切面“织入”到目标类中。在目标类的方法被调用时,代理对象会根据切点拦截方法调用并执行相应的通知逻辑。