恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

AspectJ 全注解开发详解

  • 首页
  • 资讯中心
  • /
  • AspectJ 全注解开发详解

相关资讯

Linux 开发工具(一) 软件包管理器的全方位认识 2026/10/5 6:55:39
mysql为创建普通用户并创建库赋权 2026/10/5 6:55:39
WiX Toolset 的 HarvestProjects 目标:从 MSBuild 项目自动生成 WiX 安装脚本 2026/10/5 6:50:38

最新资讯

Flask + Vue3 全栈开发:读书分享评论平台实战解析
带权并查集与前缀和:蓝桥杯“推导部分和”的图论建模
STM32定时器输入捕获测量PWM频率与占空比详解
小镇青年的人脉进化:从继承关系到开拓关系
实测8款降AI工具:AI率82%降到个位数,笔灵AI同类怎么选?
SpringBoot+Vue宠物商城项目全解析:从架构到部署

今日推荐

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单
YOLOv5 OBB旋转框训练实战:从DOTA数据准备到调参避坑全流程
Zeron 终端、Worktree 与 Diff 面板:像 IDE 一样查看并驱动你的代码变更

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

AspectJ 全注解开发详解

发布时间:2026/10/5 6:55:39
AspectJ 全注解开发详解 AspectJ 全注解开发详解AspectJ 全注解开发是指完全用注解定义切面、切点和通知不写 XML 配置文件。Spring AOP 支持 AspectJ 的注解语法配合EnableAspectJAutoProxy即可开启自动代理。这是目前 Spring 项目中最主流的 AOP 开发方式。一、全注解开发的核心步骤步骤操作注解1引入依赖spring-boot-starter-aop2开启自动代理EnableAspectJAutoProxy3定义切面AspectComponent4定义切点Pointcut5定义通知Before、After、Around等二、引入依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency这个依赖包含了spring-aop、aspectjweaver等核心库。Spring Boot 项目引入后AOP 自动配置默认开启不需要额外加EnableAspectJAutoProxy。如果是纯 Spring 项目需要手动添加ConfigurationEnableAspectJAutoProxypublicclassAopConfig{}三、定义切面切面用Aspect和Component标注。Aspect告诉 Spring 这是一个切面类Component让 Spring 扫描并注册为 Bean。AspectComponentpublicclassLogAspect{privatestaticfinalLoggerlogLoggerFactory.getLogger(LogAspect.class);// 切点和通知在这里定义}Aspect来自org.aspectj.lang.annotation包Component来自 Spring。四、定义切点切点用Pointcut定义方法返回void方法体为空。Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}Pointcut(annotation(com.example.annotation.Log))publicvoidlogAnnotation(){}Pointcut(execution(* com.example.service.*.*(..)) annotation(com.example.annotation.Log))publicvoidloggedServiceMethod(){}切点方法名就是切点的名称其他通知通过方法名引用它。切点方法本身不会被调用只是一个标识。五、五种通知1. Before 前置通知在目标方法执行前执行。Before(serviceLayer())publicvoidbefore(JoinPointjoinPoint){StringmethodNamejoinPoint.getSignature().getName();Object[]argsjoinPoint.getArgs();log.info(开始执行{}参数{},methodName,Arrays.toString(args));}2. After 后置通知在目标方法执行后执行无论是否抛出异常。After(serviceLayer())publicvoidafter(JoinPointjoinPoint){log.info(执行结束{},joinPoint.getSignature().getName());}3. AfterReturning 返回通知在目标方法正常返回后执行可以获取返回值。AfterReturning(pointcutserviceLayer(),returningresult)publicvoidafterReturning(JoinPointjoinPoint,Objectresult){log.info(返回结果{},result);}returning属性指定方法参数名Spring 会把目标方法的返回值赋给它。如果返回值是 voidresult为 null。4. AfterThrowing 异常通知在目标方法抛出异常后执行可以获取异常对象。AfterThrowing(pointcutserviceLayer(),throwingex)publicvoidafterThrowing(JoinPointjoinPoint,Exceptionex){log.error(执行异常{}异常信息{},joinPoint.getSignature().getName(),ex.getMessage());}throwing属性指定方法参数名Spring 会把目标方法抛出的异常赋给它。可以指定具体的异常类型来过滤。5. Around 环绕通知功能最全的通知可以控制目标方法是否执行、修改返回值、处理异常。Around(serviceLayer())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{StringmethodNamepjp.getSignature().getName();longstartSystem.currentTimeMillis();Objectresult;try{resultpjp.proceed();// 执行目标方法longcostSystem.currentTimeMillis()-start;log.info({} 执行成功耗时{}ms,methodName,cost);returnresult;}catch(Throwablee){longcostSystem.currentTimeMillis()-start;log.error({} 执行异常耗时{}ms,methodName,cost,e);throwe;}}ProceedingJoinPoint比JoinPoint多了一个proceed()方法用于执行目标方法。Around的返回值会作为目标方法的返回值返回所以必须返回Object且要返回proceed()的结果。六、获取连接点信息JoinPoint提供了获取目标方法信息的方法。Before(serviceLayer())publicvoidbefore(JoinPointjoinPoint){// 方法签名SignaturesignaturejoinPoint.getSignature();StringmethodNamesignature.getName();StringclassNamesignature.getDeclaringTypeName();// 方法参数Object[]argsjoinPoint.getArgs();// 目标对象ObjecttargetjoinPoint.getTarget();// 代理对象ObjectproxyjoinPoint.getThis();// 获取方法上的注解MethodSignaturemethodSignature(MethodSignature)signature;MethodmethodmethodSignature.getMethod();LoglogAnnotationmethod.getAnnotation(Log.class);}方法返回值说明getSignature()Signature方法签名getArgs()Object[]方法参数getTarget()Object目标对象getThis()Object代理对象getKind()String连接点类型七、切点表达式的组合多个切点可以用逻辑运算符组合。Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}Pointcut(annotation(com.example.annotation.Log))publicvoidlogAnnotation(){}// 与service 包下标注了 Log 的方法Pointcut(serviceLayer() logAnnotation())publicvoidloggedServiceMethod(){}// 或service 包或 dao 包下的方法Pointcut(execution(* com.example.service.*.*(..)) || execution(* com.example.dao.*.*(..)))publicvoidserviceOrDao(){}// 非service 包下没有标注 NoLog 的方法Pointcut(serviceLayer() !annotation(com.example.annotation.NoLog))publicvoidserviceWithoutNoLog(){}八、通知的执行顺序同一个切面中不同通知的执行顺序Around 前半部分 → Before → 目标方法 → AfterReturning / AfterThrowing → After Around 后半部分完整顺序Around中proceed()之前的代码Before目标方法执行AfterReturning正常返回或AfterThrowing抛出异常AfterAround中proceed()之后的代码九、多个切面的执行顺序多个切面作用于同一个方法时用Order控制顺序。数值越小优先级越高。AspectComponentOrder(1)publicclassLogAspect{// 先执行}AspectComponentOrder(2)publicclassTransactionAspect{// 后执行}对于BeforeOrder值小的先执行。对于AfterOrder值大的先执行。Around则按嵌套顺序执行。十、完整示例1. 自定义注解Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceLog{Stringvalue()default;}2. 切面AspectComponentSlf4jpublicclassLogAspect{Pointcut(annotation(com.example.annotation.Log))publicvoidlogPointcut(){}Around(logPointcut() annotation(logAnnotation))publicObjectaround(ProceedingJoinPointpjp,LoglogAnnotation)throwsThrowable{StringmethodNamepjp.getSignature().getName();StringoperationlogAnnotation.value();log.info(开始执行{}操作{},methodName,operation);longstartSystem.currentTimeMillis();try{Objectresultpjp.proceed();longcostSystem.currentTimeMillis()-start;log.info(执行成功{}耗时{}ms,methodName,cost);returnresult;}catch(Throwablee){longcostSystem.currentTimeMillis()-start;log.error(执行失败{}耗时{}ms异常{},methodName,cost,e.getMessage());throwe;}}}3. 业务方法ServicepublicclassUserService{Log(注册用户)publicUserregister(Stringname){System.out.println(注册用户name);returnnewUser(1L,name);}Log(查询用户)publicUserfindById(Longid){returnnewUser(id,张三);}}4. 测试SpringBootTestclassUserServiceTest{AutowiredprivateUserServiceuserService;TestvoidtestRegister(){userService.register(张三);}}输出开始执行register操作注册用户 注册用户张三 执行成功register耗时0ms十一、通知中获取注解参数Around通知可以直接获取方法上的注解对象这是通过annotation切点表达式实现的。Around(annotation(logAnnotation))publicObjectaround(ProceedingJoinPointpjp,LoglogAnnotation)throwsThrowable{// logAnnotation 就是方法上的 Log 注解实例StringvaluelogAnnotation.value();// ...returnpjp.proceed();}方法参数名logAnnotation必须与切点表达式annotation(logAnnotation)中的名称一致。Spring 会自动注入注解实例。十二、注意事项1. 切面本身不能被代理切面类不应该被其他切面增强否则会导致无限递归。Spring 会跳过切面类的代理。2. 切点表达式要准确execution(* com.example.service.*.*(..))只匹配service包下的类。包名或方法签名写错会导致增强不生效。3. 内部调用失效同一个类中方法 A 调用方法 BB 的增强不会生效。因为内部调用不经过代理对象。需要通过注入自身代理或AopContext.currentProxy()解决。4. Around 必须返回 proceed() 的结果// ❌ 错误返回值丢失Around(serviceLayer())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{pjp.proceed();returnnull;// 目标方法的返回值被丢弃}// ✅ 正确Around(serviceLayer())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{Objectresultpjp.proceed();returnresult;}5. AfterReturning 和 AfterThrowing 不能同时获取返回值两者互斥正常返回时执行AfterReturning抛出异常时执行AfterThrowing。6. 代理方式Spring Boot 默认使用 CGLIB 代理。如果需要 JDK 动态代理设置EnableAspectJAutoProxy(proxyTargetClass false)。十三、总结维度核心要点依赖spring-boot-starter-aop开启Spring Boot 自动开启纯 Spring 用EnableAspectJAutoProxy切面AspectComponent切点Pointcut方法返回 void方法体为空通知Before、After、AfterReturning、AfterThrowing、Around连接点JoinPoint普通通知、ProceedingJoinPoint环绕通知顺序Order控制切面优先级注意事项内部调用失效、Around 必须返回 proceed() 的结果默认代理Spring Boot 默认 CGLIBAspectJ 全注解开发是 Spring AOP 的主流方式。它把切面、切点、通知都写在 Java 类里配置简单、类型安全、可读性高。掌握Aspect、Pointcut和五种通知的用法配合切点表达式就能覆盖绝大多数横切关注点的处理需求。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号