SpringAOP
Spring AOP
不改变原有代码的情况下增强原有逻辑
实现方式
Spring支持两种AOP实现:
- Spring AOP(基于Advisor):轻量级,仅支持方法拦截。这是 Spirng 自家的
- AspectJ:功能完整,支持字段、构造器等拦截。这是三方框架
| 维度 | Spring AOP(Advisor) | AspectJ |
|---|---|---|
| 拦截范围 | 仅 Spring Bean 的 public 方法 | 任意对象、字段、构造器等 |
| 性能 | 有代理调用开销 | 无运行时开销 |
| 配置复杂度 | 简单(注解驱动) | 需配置织入器(LTW/CTW) |
| 适用场景 | 事务、日志等常见需求 | 需要拦截非Spring对象的场景 |
| 底层实现 | 基于动态代理 | 基于字节码增强 |
优先用Spring AOP:适合大多数场景(如@Transactional)
必要时用AspectJ:需要拦截非 Spring 对象或字段/构造器时
核心概念
| 概念 | 说明 | 人话 |
|---|---|---|
| Aspect(切面) | 封装横切逻辑的模块 | @Aspect 注解的类,就是我们自己定义的类 |
| Target(目标对象) | 被增强的原始对象 | 目标对象 |
| Join Point(连接点) | 程序执行的点(如方法调用、异常抛出) | 目标对象所有方法 |
| Pointcut(切点) | 选中的连接点 | 目标对象被增强的方法 |
| Advice(通知) | 切面在连接点执行的动作 | 前置、后置、返回、异常和环绕等 |
| Proxy(代理对象) | Advisor 特有 | Advisor 基于动态代理实现 |
| Weaving(织入) | AspectJ 特有 | AspectJ 需配置织入器(LTW 或 CTW 两种方式) |
通知类型
| 通知类型 | 执行时机 | 说明 |
|---|---|---|
@Before |
目标方法执行前 | 如果通知中 return 或抛出异常,目标方法不会执行 |
@AfterReturning |
目标方法 成功返回后 | 通过连接点可以拿到目标方法的返回值做一些处理 目标方法如果抛出异常,本通知不会执行 |
@AfterThrowing |
目标方法 抛出异常后 | 通过连接点可以拿到异常信息做一些处理 比如事物回滚,资源恢复等 |
@After |
目标方法 结束后(无论成败) | 无论目标方法是否异常都会执行 |
@Around |
包围目标方法(需手动调用 ProceedingJoinPoint.proceed()) |
前面4种通知的合体 |
切点表达式
更详细的切点表达式介绍 看这里
-
execution:匹配方法执行(最常用)。@Before("execution(public * com.example.service.*.*(..))") -
@annotation:匹配自定义注解标记的方法。@Around("@annotation(com.example.LogExecutionTime)")
增强 Spring bean 示例
JDK 和 cglib 动态代理增强
使用 Advisor 增强
@Aspect
@Component
public class LogAspect {
@Around("* com.example.User.sayHello(..)") // 增强 sayHello 方法
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("执行前.....");
Object result = joinPoint.proceed();
System.out.println("执行后.....");
return result;
}
}
Advisor 和 AspectJ 示例
Advisor
Advisor 更详细的介绍 看这里
@Aspect
@Component
public class LogAspect {
// 拦截Service层所有方法
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint jp) {
System.out.println("调用方法: " + jp.getSignature().getName());
}
}
AspectJ
AspectJ 更详细的介绍 看这里
@Aspect // 无需@Component!
public class SecurityAspect {
// 拦截 File 对象的构造方法调用
@After("call(java.io.File.new(..))")
public void logFileCreation() {
System.out.println("文件被创建!");
}
}

浙公网安备 33010602011771号