切点表达式 execution、within、@annotation、target、args、bean 到底各自匹配什么?protected 和包可见的方法能不能被拦?不同写法每次调用的开销一样吗?这篇在 Spring Framework 7.0.9 上逐项验证。
orderService.place("1") → 命中 [execution(* OrderService.place(..)), execution(* OrderService.*(..))→place, target(Api)→place]
orderService.cancel("1")(@Audited) → 命中 [execution(* OrderService.*(..))→cancel, @annotation(Audited)→cancel, target(Api)→cancel]
orderService.ping() → 命中 [execution(* OrderService.*(..))→ping, target(Api)→ping]
orderService.callInternal()(内部调 place) → 命中 [execution(* OrderService.*(..))→callInternal, target(Api)→callInternal]
payService.pay(5) → 命中 [within(PayService)→pay, @within(Marked)→pay, execution(public * *(..)) && within(PayService)→pay]
payService.refund(5) → 命中 [execution(* *Service.re*(..))→PayService.refund, within(PayService)→refund, @within(Marked)→refund, execution(public * *(..)) && within(PayService)→refund]
userService.find(7L) → 命中 [execution(find(long)) && args(id) 拿到 id=7, bean(userService)→find]
orderService.pkgPrivate()(包可见) → 命中 [execution(* OrderService.*(..))→pkgPrivate, target(Api)→pkgPrivate]
orderService.prot()(protected) → 命中 [execution(* OrderService.*(..))→prot, target(Api)→prot]execution 按签名,within 与 @within 按类,@annotation 按方法注解,target、args、bean 按运行时对象、参数和 Bean 名。
没有切面:每次调用 2、1、1 ns;通知执行次数 0;不是代理 execution(...):每次调用 80、197、80 ns;通知执行次数 5000000;是代理 execution(...) && args(id):每次调用 192、210、189 ns;通知执行次数 5000000;是代理 @annotation(Audited):每次调用 215、250、149 ns;通知执行次数 5000000;是代理 target(Api):每次调用 221、228、182 ns;通知执行次数 5000000;是代理 execution(...) && args(String)(m 的参数是 long,静态就不可能匹配):每次调用 0、1、1 ns;通知执行次数 0;不是代理
带 args、@annotation、target 的切点每次调用要多判断一次,比单纯 execution 贵一倍左右。