尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
优化切点表达式的使用
优化切点表达式的使用切点表达式写得好不好直接影响 AOP 的准确性、性能和可维护性。写得宽了会拦截不该拦截的方法写得窄了会漏掉需要增强的方法写得乱了后期根本看不懂。下面从几个角度讲怎么优化。一、用 Pointcut 抽取公共切点多个通知引用同一个切点表达式时不要重复写。用Pointcut定义一次其他地方通过方法名引用。不推荐Before(execution(* com.example.service.*.*(..)))publicvoidbefore(){}AfterReturning(execution(* com.example.service.*.*(..)))publicvoidafterReturning(){}AfterThrowing(execution(* com.example.service.*.*(..)))publicvoidafterThrowing(){}推荐Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}Before(serviceLayer())publicvoidbefore(){}AfterReturning(serviceLayer())publicvoidafterReturning(){}AfterThrowing(serviceLayer())publicvoidafterThrowing(){}表达式修改时只需要改一处。二、用注解切点替代包扫描切点execution(* com.example.service.*.*(..))按包匹配粒度粗。随着项目变大service 包下可能有几十个类全部拦截未必是想要的。用自定义注解精确控制哪些方法需要增强。定义注解Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceLog{Stringvalue()default;}切点Pointcut(annotation(com.example.annotation.Log))publicvoidlogPointcut(){}使用ServicepublicclassUserService{Log(注册用户)publicvoidregister(Useruser){}// 这个方法不需要增强不加注解即可publicUserfindById(Longid){}}注解切点的优势精确到方法级别不会误伤。语义清晰看代码就知道哪些方法被增强。可以携带参数如操作描述通知中能直接读取。三、切点表达式要精确1. 限定返回类型// ❌ 太宽所有返回类型execution(*com.example.service.*.*(..))// ✅ 只匹配返回 User 的方法execution(com.example.entity.Usercom.example.service.*.*(..))// ✅ 只匹配返回 void 的方法execution(voidcom.example.service.*.*(..))2. 限定参数类型// ❌ 太宽任意参数execution(*com.example.service.*.*(..))// ✅ 只匹配第一个参数是 Long 的方法execution(*com.example.service.*.*(Long,..))// ✅ 只匹配无参方法execution(*com.example.service.*.*())3. 限定方法名前缀// ❌ 太宽所有方法execution(*com.example.service.*.*(..))// ✅ 只匹配 save、update、delete 开头的方法execution(*com.example.service.*.save*(..))||execution(*com.example.service.*.update*(..))||execution(*com.example.service.*.delete*(..))4. 精确到类// ❌ 太宽service 包下所有类execution(*com.example.service.*.*(..))// ✅ 只匹配 UserService 类execution(*com.example.service.UserService.*(..))// ✅ 只匹配 UserService 和 OrderServiceexecution(*com.example.service.UserService.*(..))||execution(*com.example.service.OrderService.*(..))四、用组合切点表达复杂逻辑多个条件组合时用、||、!精确表达。Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}Pointcut(annotation(com.example.annotation.Log))publicvoidlogAnnotation(){}Pointcut(serviceLayer() logAnnotation())publicvoidloggedServiceMethod(){}Pointcut(serviceLayer() !annotation(com.example.annotation.NoLog))publicvoidserviceWithoutNoLog(){}实际场景// 拦截 service 包下所有 public 方法但排除 get 和 find 开头的方法Pointcut(execution(public * com.example.service.*.*(..)) !execution(* com.example.service.*.get*(..)) !execution(* com.example.service.*.find*(..)))publicvoidwriteOperations(){}五、按业务维度拆分切点不要把所有逻辑塞进一个切面按业务维度拆分每个切面只关注一件事。不推荐AspectComponentpublicclassAllInOneAspect{Around(annotation(Log))publicObjectlog(ProceedingJoinPointpjp){...}Around(annotation(Cache))publicObjectcache(ProceedingJoinPointpjp){...}Around(annotation(RateLimit))publicObjectrateLimit(ProceedingJoinPointpjp){...}}推荐AspectComponentOrder(1)publicclassLogAspect{Around(annotation(Log))publicObjectlog(ProceedingJoinPointpjp){...}}AspectComponentOrder(2)publicclassCacheAspect{Around(annotation(Cache))publicObjectcache(ProceedingJoinPointpjp){...}}AspectComponentOrder(3)publicclassRateLimitAspect{Around(annotation(RateLimit))publicObjectrateLimit(ProceedingJoinPointpjp){...}}每个切面职责单一用Order控制顺序便于维护和调试。六、用 within 和 target 区分粒度// 匹配标注了 Service 的类中所有方法within(org.springframework.stereotype.Service)// 匹配标注了 RestController 的类中所有方法within(org.springframework.web.bind.annotation.RestController)// 匹配目标对象是 UserService 类型的方法target(com.example.service.UserService)within适合按类级别统一增强annotation适合按方法级别精确增强。七、切点表达式的可读性优化1. 长表达式拆分成多个 Pointcut// ❌ 难读Around(execution(* com.example.service.*.*(..)) (annotation(com.example.annotation.Log) || annotation(com.example.annotation.Audit)) !annotation(com.example.annotation.Skip))publicObjectaround(ProceedingJoinPointpjp){...}// ✅ 拆分成可读的切点Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}Pointcut(annotation(com.example.annotation.Log) || annotation(com.example.annotation.Audit))publicvoidauditable(){}Pointcut(!annotation(com.example.annotation.Skip))publicvoidnotSkipped(){}Around(serviceLayer() auditable() notSkipped())publicObjectaround(ProceedingJoinPointpjp){...}2. 用注释说明切点意图/** * 匹配 service 包下所有增删改方法 * 排除查询方法避免事务和日志对查询造成性能影响 */Pointcut(execution(* com.example.service.*.*(..)) !execution(* com.example.service.*.get*(..)) !execution(* com.example.service.*.find*(..)))publicvoidwriteOperations(){}八、性能优化1. 避免过于宽泛的切点// ❌ 拦截所有方法包括 JDK 内部方法性能开销大Around(execution(* *(..)))// ✅ 限定包路径Around(execution(* com.example..*.*(..)))2. 用 annotation 替代 executionannotation在运行时检查方法注解比execution的包扫描匹配更快因为注解信息在类加载时已经解析好。// 较慢需要匹配包路径和方法签名Around(execution(* com.example.service.*.*(..)))// 较快直接检查方法注解Around(annotation(com.example.annotation.Log))3. 避免在切点中写复杂逻辑切点表达式只做匹配复杂逻辑放到通知里。// ❌ 切点中写复杂条件Around(execution(* com.example.service.*.*(..)) args(id, ..) annotation(Log))publicObjectaround(ProceedingJoinPointpjp,Longid,Loglog){...}// ✅ 切点简单逻辑放通知里Around(serviceLayer() logPointcut())publicObjectaround(ProceedingJoinPointpjp,Loglog){...}九、常见优化对比优化点不推荐推荐切点复用每个通知重复写表达式Pointcut抽取匹配粒度execution(* service.*.*(..))annotation(Log)返回类型*匹配所有精确指定返回类型参数类型(..)匹配所有(Long, ..)精确匹配切面拆分一个切面处理所有增强按职责拆分成多个切面表达式可读性一长串表达式拆分成多个命名切点性能宽泛匹配注解匹配十、完整示例AspectComponentOrder(1)Slf4jpublicclassOperationLogAspect{/** * 匹配所有标注了 Log 的方法 * 精确到方法级别不会误伤其他方法 */Pointcut(annotation(com.example.annotation.Log))publicvoidlogPointcut(){}/** * 匹配 service 包下所有 public 方法 * 排除查询方法只关注写操作 */Pointcut(execution(public * com.example.service.*.*(..)) !execution(* com.example.service.*.get*(..)) !execution(* com.example.service.*.find*(..)) !execution(* com.example.service.*.query*(..)))publicvoidwriteOperations(){}Around(logPointcut() annotation(logAnnotation))publicObjectlog(ProceedingJoinPointpjp,LoglogAnnotation)throwsThrowable{StringmethodNamepjp.getSignature().getName();StringoperationlogAnnotation.value();log.info(开始{}操作{},methodName,operation);longstartSystem.currentTimeMillis();try{Objectresultpjp.proceed();log.info(完成{}耗时{}ms,methodName,System.currentTimeMillis()-start);returnresult;}catch(Throwablee){log.error(失败{}耗时{}ms异常{},methodName,System.currentTimeMillis()-start,e.getMessage());throwe;}}}十一、总结优化方向具体做法复用用Pointcut抽取公共切点精确用注解切点替代包扫描拆分按职责拆分成多个切面组合用、||、!组合切点可读长表达式拆分成命名切点加注释性能避免宽泛匹配优先用注解匹配顺序用Order明确切面优先级切点表达式的优化核心是精确、复用、可读。精确让增强只作用在需要的地方复用让表达式集中管理可读让后期维护不费劲。优先用注解切点按职责拆分切面用Pointcut抽取公共逻辑这三点做到了切点表达式基本就不会出问题。
RELATED

相关推荐

EtherCAT与FSoE安全通信实战:从站芯片机制与配置避坑指南

EtherCAT与FSoE安全通信实战:从站芯片机制与配置避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/9 2:42:15
WHEA_UNCORRECTABLE_ERROR蓝屏排查:从日志到硬件的完整定位流程

WHEA_UNCORRECTABLE_ERROR蓝屏排查:从日志到硬件的完整定位流程

1. 从一次深夜蓝屏说起:WHEA_UNCORRECTABLE_ERROR到底在报什么警凌晨两点,渲染到87%的工程文件突然卡死,屏幕一蓝,一行冰冷的白字跳出来:WHEA_UNCORRECTABLE_ERROR。重启之后一切正常,你以为只是偶然&#…

📅 2026/10/9 2:42:15
Java图书管理系统实战:Servlet+JSP+MySQL从架构到部署避坑全解析

Java图书管理系统实战:Servlet+JSP+MySQL从架构到部署避坑全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/9 2:42:15
MORE NEWS

更多资讯

📰

MASTG iOS 非生产资源详解:如何识别并从生产构建中剔除调试日志、测试端点与开发凭据

文档教程网络安全 【免费下载链接】mastg The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security W…

📰

AI 为什么能学习?以及AI 与人脑的本质差距是什么?

一、为什么要对比两者人工神经网络的设计灵感来源于生物神经系统,但经过几十年发展,Transformer 大模型的实现机制与真实人脑已经差异巨大。理解两者的对应关系和本质区别,是理解大模型能力边界的关键。核心命题:两者都遵循"…

📰

2026年SMT贴片打样与量产产线选型指南

面对2026年AI眼镜、AI算力模组、机器人、汽车电子、医疗电子等下游应用的持续放量,SMT贴片加工与PCBA代工代料的需求正在爆发式增长。但许多研发企业、品牌方和硬件创业者在深圳及珠三角寻找SMT贴片加工厂时,常常会遇到一个核心困惑:如何在打…

📰

智慧政务AI大模型应用方案:从私有化部署到RAG落地实践

简介:这是一份面向政府数字化转型的智慧政务AI大模型应用方案演示文稿,适合政务信息化主管、AI架构师和项目规划人员阅读,旨在解决审批周期长、数据分散、风险防控难等典型问题。方案从实施背景与2024年度目标切入,围绕智能问答引…

📰

Julep mem-mcp Phase 2 兼容:让 .ctx 提示词包在 dotctx 加载器中忠实落地

AI AgentAgent 框架后端 【免费下载链接】julep Julep — durable, composable AI agents. Flows that crash and resume, retry safely, and explain every step. 项目地址: https://gitcode.com/gh_mirrors/ju/julep 点击查看 免费下载 导读 本文以 Julep 仓库中…

📰

计及氢能的综合能源优化调度:Matlab建模与实现

刚接这个课题的时候,我其实有点不以为然,觉得无非就是把氢气设备塞进综合能源系统里,再跑一个优化调度。但真正动手去做矩阵建模和Matlab代码实现,才发现里面藏着不少坑:电解槽的启停逻辑怎么线性化?储氢罐…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬