一、概念部分
1.切入点表达式
切入点表达式(Pointcut Expressions)是 Spring AOP 中用于定义切面的切入点逻辑的关键语法。它通过精确描述程序中的哪些连接点(Join Point)需要执行通知逻辑,决定了 AOP 的应用范围。
切入点表达式常与通知类型配合使用,用于描述如下信息:
-
目标方法的修饰符
-
返回类型
-
包名与类名
-
方法名
-
参数类型和个数
-
异常类型
2. 切入点表达式的常见语法
语法格式如下:
execution([修饰符] 返回值 包名.类名.方法名(参数) [throws 异常类型])
其中:
-
[修饰符]
可以省略(如public
、protected
) -
返回值
支持通配符*
表示任意返回值 -
包名
、类名
和方法名
可以使用通配符匹配部分内容 -
(参数)
支持*
表示任意参数 -
throws
部分可以省略
3. 常见通配符的含义
-
*
:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分。 -
..
:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数 -
&&
、||
、!
:用于组合表达式,分别表示逻辑与、逻辑或、逻辑非
二、示例代码解读
@Slf4j
@Component
@Aspect
public class MyAspect2 {
@Before("execution(public void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")
@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")
@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(*))")
@Before("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
@Before("execution(* com.itheima.service.impl.*.*(..))")
@Before("execution(* com.itheima.service.impl.DeptServiceImpl.del*(..))")
@Before("execution(* com..service.*.*(..))")
@Before("execution(* *(..))") //慎用!!!!!!!!!! --- 性能越差
@Before("execution(* com.itheima.service.impl.DeptServiceImpl.list()) || " +
"execution(* com.itheima.service.impl.DeptServiceImpl.save(*))")
@Before("execution(* com.itheima.service.DeptService.*(..))") //切入点表达式可以基于接口进行匹配
@Before("execution(public void com.itheima.service.impl.DeptServiceImpl.delete(..))")
@Before("@annotation(com.itheima.anno.Log)")
public void before(){
log.info("MyAspect2 -> before ...");
}
}
1. 注解解读
-
@Slf4j
:由 Lombok 提供的日志注解,生成log
对象。 -
@Component
:将该类声明为 Spring 容器中的一个组件。 -
@Aspect
:声明该类为切面类,启用 AOP 功能。 -
@Before
:声明前置通知,目标方法在执行前触发before()
方法。
2. 切入点表达式分析
精确匹配
execution(public void com.itheima.service
.impl.DeptServiceImpl.delete(java.lang.Integer))
-
精确匹配
DeptServiceImpl
类中的delete
方法,该方法的签名必须完全一致。
省略修饰符匹配
execution(void com.itheima.service.impl
.DeptServiceImpl.delete(java.lang.Integer))
-
忽略访问修饰符(
public
、protected
、private
),匹配范围放宽。
参数通配符匹配
execution(void com.itheima.service.impl.DeptServiceImpl.delete(*))
-
匹配
delete
方法,允许参数为任意类型的单个参数。
方法名称通配符匹配
execution(* com.itheima.service.impl.DeptServiceImpl.del*(..))
-
匹配
DeptServiceImpl
类中所有以del
开头的方法,参数数量与类型不限。
包与类的通配符匹配
execution(* com.itheima.service.impl.*.*(..))
-
匹配
impl
包下所有类的所有方法,参数数量与类型不限。
execution(* com..service.*.*(..))
-
匹配
com
包及其子包下所有类的所有方法。
基于注解匹配
@annotation(com.itheima.anno.Log)
-
匹配所有标注了
@Log
注解的方法。
组合条件匹配
execution(* com.itheima.service.impl.DeptServiceImpl.list())
|| execution(* com.itheima.service.impl.DeptServiceImpl.save(*))
-
使用逻辑运算符
||
组合表达式,匹配list
方法或save
方法,同时需要注意方法的参数匹配规则。list
方法必须无参,而save
方法可以接受单个任意类型的参数。
三、总结部分
书写建议
-
所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:
findXxx
,updateXxx
。 -
描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性。
-
在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名尽量不使用
..
,使用*
匹配单个包。
-
切入点表达式的核心作用
-
用于定义 AOP 的目标范围。
-
支持多种匹配方式(精确匹配、通配符匹配、基于注解等)。
-
结合逻辑运算符,可实现复杂的业务逻辑需求。
-
-
常见场景与注意事项
-
精确匹配适用于特定方法的切入逻辑。
-
包与类的通配符匹配适用于模块级别的切面应用。
-
基于注解的匹配方式更灵活,减少了与方法签名的强耦合。
-
全局匹配(如
execution(* *(..))
)慎用,可能导致性能问题。
-