news 2026/4/23 17:07:00

Java 注解与反射实战:手把手实现自定义日志与参数校验注解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 注解与反射实战:手把手实现自定义日志与参数校验注解

好的,我们来一步步手写两个非常实用的自定义注解 + 反射实现:

  1. @LogExecution:方法执行前后自动打印日志(入参 + 返回值 + 耗时)
  2. @NotBlankParam:方法参数非空/非空白校验(类似 @NotBlank 但作用于方法参数,且用纯反射实现,不依赖 Spring/Hibernate Validator)

我们先用最原始的反射方式实现(不依赖 AOP / Spring),适合理解原理、工具类、测试框架、轻量 SDK 等场景。然后简单提一下如何升级到 Spring AOP 方式。

第一部分:@LogExecution 日志注解(反射实现)

1. 定义注解
importjava.lang.annotation.*;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceLogExecution{Stringvalue()default"";// 可自定义日志前缀booleanlogArgs()defaulttrue;// 是否打印入参booleanlogResult()defaulttrue;// 是否打印返回值booleanlogTime()defaulttrue;// 是否打印耗时}
2. 反射工具类(核心调用逻辑)
importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.lang.reflect.Method;importjava.util.Arrays;publicclassLogExecutionUtil{privatestaticfinalLoggerlog=LoggerFactory.getLogger(LogExecutionUtil.class);/** * 包装执行目标方法,自动加日志 */publicstaticObjectinvokeWithLogging(Objecttarget,Methodmethod,Object[]args)throwsThrowable{LogExecutionanno=method.getAnnotation(LogExecution.class);if(anno==null){// 没有注解 → 直接执行returnmethod.invoke(target,args);}Stringprefix=anno.value().isEmpty()?method.getName():anno.value();StringBuilderlogPrefix=newStringBuilder("[").append(prefix).append("] ");// 打印入参if(anno.logArgs()){StringargsStr=args==null?"null":Arrays.toString(args);log.info("{}开始执行 → 参数: {}",logPrefix,argsStr);}longstart=System.nanoTime();try{Objectresult=method.invoke(target,args);// 打印返回值if(anno.logResult()){log.info("{}执行完成 → 返回: {}",logPrefix,result);}// 打印耗时if(anno.logTime()){doublems=(System.nanoTime()-start)/1_000_000.0;log.info("{}耗时: {} ms",logPrefix,String.format("%.3f",ms));}returnresult;}catch(Throwablee){log.error("{}执行异常",logPrefix,e);throwe;}}}
3. 使用示例
publicclassUserService{@LogExecution(value="创建用户",logArgs=true,logResult=true,logTime=true)publicUsercreateUser(Stringusername,intage){if(age<0)thrownewIllegalArgumentException("年龄不能为负");returnnewUser(username,age);}@LogExecution("批量删除")// 使用默认值publicvoidbatchDelete(List<Long>ids){System.out.println("删除 "+ids.size()+" 条记录");}}
4. 如何调用(代理 / 手动包装)

最简单的方式:写一个代理类或在调用处手动用invokeWithLogging

// 手动调用方式UserServiceservice=newUserService();Methodmethod=UserService.class.getMethod("createUser",String.class,int.class);LogExecutionUtil.invokeWithLogging(service,method,newObject[]{"alice",25});

更常见的是结合动态代理(JDK Proxy / ByteBuddy / CGLIB)使用。

第二部分:@NotBlankParam 参数非空校验(反射实现)

1. 定义注解(可重复)
importjava.lang.annotation.*;@Repeatable(NotBlankParams.class)@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceNotBlankParam{intindex()default-1;// 参数下标(从0开始),-1表示自动推断(推荐)Stringmessage()default"参数不能为空且不能为纯空白";}
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceNotBlankParams{NotBlankParam[]value();}
2. 校验工具类
importjava.lang.reflect.Method;importjava.lang.reflect.Parameter;importjava.util.Objects;publicclassParamValidator{publicstaticvoidvalidateParams(Objecttarget,Methodmethod,Object[]args){Parameter[]parameters=method.getParameters();Annotation[][]paramAnnos=method.getParameterAnnotations();for(inti=0;i<parameters.length;i++){for(Annotationanno:paramAnnos[i]){if(annoinstanceofNotBlankParam){NotBlankParamnotBlank=(NotBlankParam)anno;intidx=notBlank.index()>=0?notBlank.index():i;if(idx>=args.length){thrownewIllegalArgumentException("注解 index 越界");}Objectvalue=args[idx];if(value==null||(valueinstanceofString&&((String)value).trim().isEmpty())){thrownewIllegalArgumentException(notBlank.message()+" (参数位置: "+idx+")");}}}}}}
3. 使用示例
publicclassOrderService{publicvoidcreateOrder(@NotBlankParamStringorderNo,@NotBlankParam(message="收货人姓名必填")StringreceiverName,Stringremark){// remark 不校验System.out.println("创建订单:"+orderNo);}}
4. 调用方式(同样结合代理)
// 在方法执行前先校验ParamValidator.validateParams(target,method,args);// 再执行方法method.invoke(target,args);

第三部分:升级方案(生产级常用方式)

场景推荐方式优点实现复杂度
学习/理解原理纯反射 + 手动代理最清晰,理解最透彻★★★☆☆
轻量工具类/SDKJDK动态代理 / ByteBuddy无 Spring 依赖,体积小★★★★☆
Spring Boot 项目Spring AOP + @Aspect零侵入、最优雅★★☆☆☆
高性能场景Annotation Processor + APT / 字节码生成编译期生成代码,无反射开销★★★★★
Spring AOP 快速示例(@LogExecution)
@Aspect@ComponentpublicclassLogExecutionAspect{@Around("@annotation(logAnno)")publicObjectaround(ProceedingJoinPointjoinPoint,LogExecutionlogAnno)throwsThrowable{// 前置日志、入参// proceed()// 后置日志、耗时、返回值}}

小结 & 进阶方向

  • 学会了@Retention(RUNTIME)+反射读取注解的基本套路
  • 掌握了方法参数注解的获取方式(method.getParameterAnnotations()
  • 明白了自定义注解 + 反射的两种主要用途:日志追踪参数/返回值校验
  • 能自己写出简易的方法切面工具(不依赖框架)

接下来想深入哪个方向?

A. 写一个完整的JDK动态代理包装器(自动扫描 @LogExecution / @NotBlankParam)
B. 实现Spring AOP版本(AspectJ风格)
C. 做参数校验的支持分组 / 支持自定义消息国际化
D. 用Annotation Processor在编译期校验注解使用是否合法
E. 结合@Around做更复杂的场景(事务 + 日志 + 校验 一条龙)

告诉我字母,我继续带你写代码!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 13:19:48

Redis 常见的面试专题:缓存击穿、缓存雪崩、缓存穿透、什么是布隆过滤器、什么是延时双删、持久化的方式、Redis 分布式锁、I/O 多路复用等等

Redis 常见的面试专题确实非常高频&#xff0c;几乎每家大厂/中大型公司后端/架构岗面试都会深挖。下面我把你列的这些点&#xff08;缓存击穿、缓存雪崩、缓存穿透、布隆过滤器、延时双删、持久化方式、Redis 分布式锁、I/O 多路复用&#xff09;全部覆盖&#xff0c;结合2025…

作者头像 李华
网站建设 2026/4/23 15:27:54

【Django毕设源码分享】Django的基于web的共青团员信息管理系统的设计与实现的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/23 11:32:40

云服务器CVM 云主机 云计算服务器 弹性云服务器-腾讯云

云服务器CVM概述腾讯云服务器CVM&#xff08;Cloud Virtual Machine&#xff09;是一种弹性计算服务&#xff0c;提供可扩展的虚拟化计算资源。用户无需购买物理硬件&#xff0c;即可快速部署应用&#xff0c;支持按需付费和灵活配置。CVM适用于Web应用、大数据分析、游戏服务等…

作者头像 李华
网站建设 2026/4/23 14:27:49

云服务器哪家好用又实惠?一文读懂四大实惠云服务商深度解析

云服务器性价比对比&#xff1a;四大主流服务商解析选择云服务器时&#xff0c;需综合考虑性能、价格、稳定性及售后服务。以下对阿里云、腾讯云、华为云和AWS&#xff08;亚马逊云&#xff09;四大服务商进行深度对比&#xff0c;涵盖适用场景、价格策略及核心优势。阿里云&am…

作者头像 李华
网站建设 2026/4/22 21:55:21

适合ASMR创作的细腻音效库有哪些?(2026最新推荐)

根据艾瑞咨询发布的《2025年中国音频内容市场研究报告》&#xff0c;ASMR内容消费量年均增长率达24%&#xff0c;用户对音效质感的敏感度显著提升。这份报告指出&#xff0c;高品质的细腻音效库如同创作者的调色盘&#xff0c;能赋予作品独特的听觉指纹。在2026年&#xff0c;A…

作者头像 李华
网站建设 2026/4/2 2:41:29

让Agent画思维导图稳固长期记忆:新框架实现稳定长期学习,准确率提升38%

传统RAG在“长期记忆管理”和“持续学习承载能力”两个层面&#xff0c;正在同时暴露出结构性瓶颈。 思维导图曾被证明可以帮助学习障碍者快速提升成绩&#xff0c;那么当前已经可堪一用的智能体系统如果引入类似工具是否可以帮助改善长期学习记忆能力呢&#xff1f;有研究团队…

作者头像 李华