SpringBoot自定义注解、AOP打印日志
前言
在SpringBoot中使用自定义注解、aop切面打印web请求日志。主要是想把controller的每个request请求日志收集起来,调用接口、执行时间、返回值这几个重要的信息存储到数据库里,然后可以使用火焰图统计接口调用时长,平均响应时长,以便于我们对接口的调用和执行情况及时掌握。添加依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version> 2.1 . 4 .RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version> 2.1 . 4 .RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version> 2.1 . 4 .RELEASE</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version> 2.8 . 5 </version> </dependency> |
自定义注解
1 2 3 4 5 6 7 8 9 | import java.lang.annotation.*; @Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.METHOD}) @Documented public @interface WebLogger { String value() default "" ; } |
AOP定义切面、切点
在实现切面之前先要了解几个aop的注解:
- @Aspect、
- @Pointcut 定义切点,后面跟随一个表达式,表达式可以是一个注解,也可以具体到方法级别。
- @Before
- @After
- @Around
实现切面,在before方法里统计request请求相关参数,在around方法里计算接口调用时间。这里统计请求的参数时有个bug,joinpoint.getArgs返回值是一个Object数组,但是数组里只有参数值,没有参数名。还没找到解决办法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | @Aspect @Component public class WebLoggerAspect { @Pointcut ( "@annotation(com.zhangfei.anno.WebLogger)" public void log() {} @Around ( "log()" ) public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime=System.currentTimeMillis(); Object result=joinPoint.proceed(); System.out.println( "Response:" + new Gson().toJson(result)); System.out.println( "耗时:" +(System.currentTimeMillis()-startTime)); return result; } @Before ( "log()" ) public void doBefore(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); System.out.println( "==================Start=================" ); System.out.println( "URL:" + request.getRequestURL().toString()); System.out.println( "Description:" + getLogValue(joinPoint)); System.out.println( "Method:" + request.getMethod().toString()); //打印controller全路径及method System.out.println( "Class Method:" + joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName()); System.out.println( "客户端IP:" + request.getRemoteAddr()); System.out.println( "请求参数:" + new Gson().toJson(joinPoint.getArgs())); } private String getLogValue(JoinPoint joinPoint) { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); WebLogger webLogger = method.getAnnotation(WebLogger. class ); return webLogger.value(); } @After ( "log()" ) public void doAfter() { System.out.println( "==================End=================" ); } } |
怎么使用注解?
这里就直接在你的web请求方法上直接添加WebLogger注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | @Controller @RequestMapping ( "/student" ) public class StudentController { private final Logger logger= LoggerFactory.getLogger(StudentController. class ); @GetMapping ( "/list" ) @WebLogger ( "学生列表" ) public @ResponseBody List<Student> list(){ ArrayList<Student> list= new ArrayList<>(); Student student0= new Student( 1 , "kobe" , 30 ); Student student1= new Student( 2 , "james" , 30 ); Student student2= new Student( 3 , "rose" , 30 ); list.add(student0); list.add(student1); list.add(student2); return list; } @WebLogger ( "学生实体" ) @RequestMapping ( "/detail" ) public @ResponseBody Student student( int id){ return new Student( 1 , "kobe" , 30 ); } }<br><br> |
切面日志输出效果
总结
从头条上一位朋友文章评论上看到有人提出,在分布式部署的环境中,出现高并发时日志打印会出现错乱的情况,这里还需要把线程id或者声明一个guid, 存入ThreadLoal中统计使用。当然更多的人简历还是使用ELK等分布式日志解决方法,好吧,这些还有待于自己部署环境去尝试。
作者:sword-successful
出处:https://www.cnblogs.com/sword-successful/p/10850168.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
博客地址: | http://www.cnblogs.com/sword-successful/ |
博客版权: | 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。 如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。 |
分类:
【框架】SpringBoot
标签:
Spring Boot
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· 一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略