这是一个非常经典的 Spring AOP 使用问题,下面我来从 原理 + 实践 + 优劣 的角度帮你全面解释:
✅ 问题重述
你发现有两种写法:
✅ 写法一:切点表达式单独作为方法使用
@Pointcut("execution(* com.example.service..*(..))")
public void serviceMethods() {} // 切点定义
@Before("serviceMethods()")
public void logBefore() {
System.out.println("Before service method");
}
✅ 写法二:切点表达式直接写在通知上
@Before("execution(* com.example.service..*(..))")
public void logBefore() {
System.out.println("Before service method");
}
🧠 为什么有两种写法?
📌 原因本质上是:
单独写成方法的切点是为了复用、提高可读性和可维护性。
✅ 区别解析
| 比较项 | 写在注解中(内联表达式) | 单独写成 @Pointcut 方法 |
|---|---|---|
| 简洁性 | ✅ 简单、快速 | ❌ 多一层方法调用 |
| 可读性 | ❌ 表达式长时难读 | ✅ 方法名具有语义 |
| 可复用性 | ❌ 不可复用,冗余 | ✅ 多个通知可复用一个切点 |
| 推荐场景 | 简单、一次性使用的切点 | 复杂、需要复用或文档化的切点 |
✅ 举例说明复用价值
比如多个通知用同一个切点:
@Pointcut("execution(* com.example.service..*(..))")
public void serviceMethods() {}
@Before("serviceMethods()")
public void beforeLog() {}
@After("serviceMethods()")
public void afterLog() {}
@Around("serviceMethods()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// ...
}
这样写更清晰、也更方便维护。
🔍 注意:@Pointcut 注解的方法必须是空的,且只能返回 void。
因为它只是定义一个切点表达式,并不会真正执行什么逻辑。
✅ 总结
| 问题 | 回答 |
|---|---|
| 为什么有些切点单独写方法? | 为了复用、提高可读性、方便维护 |
| 为什么有些切点直接写在通知上? | 简单场景下更快速、简洁 |
| 推荐用法? | 简单场景可内联,复杂或复用场景建议独立定义 |

被折叠的 条评论
为什么被折叠?



