在 Spring AOP 中:
- Advice :通知,即切面在某个连接点上要执行的动作,如
@Before、@After、@Around等。 - Pointcut:切入点,定义"在哪些方法上应用通知"。
- Aspect:切面,由 Pointcut + Advice 组成。
Spring AOP 借用了 AspectJ 的表达式语法来定义 Pointcut,但底层实现仍是 Spring 自己的动态代理(JDK Proxy 或 CGLIB),并非 AspectJ 的编译期/加载期织入。
两种定义 Pointcut 的方式
注解方式(主流推荐)
java
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.example.service..*.*(..))")
public void servicePointcut() {}
@Before("servicePointcut()")
public void before(JoinPoint jp) {
System.out.println("方法执行前: " + jp.getSignature());
}
}
配合 @EnableAspectJAutoProxy 或 <aop:aspectj-autoproxy/> 启用。
XML 配置方式
XML
<aop:config>
<aop:aspect ref="loggingAspect">
<aop:pointcut id="servicePointcut"
expression="execution(* com.example.service..*.*(..))"/>
<aop:before method="before" pointcut-ref="servicePointcut"/>
</aop:aspect>
</aop:config>
这里 <aop:pointcut> 标签直接在 XML 中定义切入点表达式,expression 属性的写法与注解完全一致。
两者的对比
| 维度 | 注解方式 | XML 方式 |
|---|---|---|
| 配置位置 | 与代码内聚 | 与代码分离 |
| 编译期检查 | 有 | 无 |
| 切点组合复用 | 支持(可通过方法名引用组合) | 不支持命名切点组合 |
| 适用场景 | 现代项目、Spring Boot | 遗留系统、需集中管控 |
官方文档也明确指出,XML 方式的局限之一就是无法像注解那样通过命名切点的组合来构建更复杂的表达式。
AspectJ
AspectJ 的表达式语法是一套用来描述"哪些连接点需要被拦截"的匹配规则。Spring AOP 借用了这套语法,但只支持其中一部分,底层仍是动态代理。
最核心:execution 表达式
execution(修饰符? 返回值 包名.类名.方法名(参数) 异常?)
java
// 任意公共方法
execution(public * *(..))
// service 包及其子包下所有类的所有方法
execution(* com.example.service..*.*(..))
// 返回 String,且方法名以 get 开头
execution(String *..get*(..))
通配符:
| 符号 | 含义 |
| * | 匹配任意单个字符(类名、方法名、返回类型等) |
| .. | 在包路径中表示"当前包及所有子包";在参数中表示"任意个数、任意类型的参数" |
+ |
匹配指定类及其子类(如 UserService+) |
|---|
简单记忆:日常开发 90% 的场景用 execution 就够了 ,需要按注解拦截时用 @annotation,按 Bean 名称拦截时用 bean。