Spring Boot如何通过自定义注解实现日志打印详解
作者:溪源的奇思妙想 发布时间:2022-07-04 14:10:18
前言
在我们日常的开发过程中通过打印详细的日志信息能够帮助我们很好地去发现开发过程中可能出现的Bug,特别是在开发Controller层的接口时,我们一般会打印出Request请求参数和Response响应结果,但是如果这些打印日志的代码相对而言还是比较重复的,那么我们可以通过什么样的方式来简化日志打印的代码呢?
SpringBoot 通过自定义注解实现权限检查可参考我的博客:SpringBoot 通过自定义注解实现权限检查
正文
Spring AOP
Spring AOP 即面向切面,是对OOP面向对象的一种延伸。
AOP机制可以让开发者把业务流程中的通用功能抽取出来,单独编写功能代码。在业务流程执行过程中,Spring框架会根据业务流程要求,自动把独立编写的功能代码切入到流程的合适位置。
我们通过AOP机制可以实现:Authentication 权限检查、Caching 缓存、Context passing 内容传递、Error handling 错误处理、日志打印等功能,这里我们讲一下怎么用Spring AOP来实现日志打印。
SpringBoot通过自定义注解实现日志打印
Maven依赖
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<optional>true</optional>
</dependency>
<!--Spring AOP-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
ControllerMethodLog.class自定义注解
@Retention: 用来修饰注解,是注解的注解,称为元注解。
@Target:用来说明对象的作用范围
@Documented:用来做标记使用
/**
* 自定义注解用于打印Controller层方式日志
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ControllerMethodLog {
}
这里特别讲一下@Retention,按生命周期来划分可分为3类:
RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃(运行时去动态获取注解信息);
RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期(在编译时进行一些预处理操作);
RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在(做一些检查性的操作);
这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。
Spring AOP切面方法的执行顺序
这里简单介绍一下,切面的执行方法和其执行顺序:
@Around 通知方法将目标方法封装起来
@Before 通知方法会在目标方法调用之前执行
@After 通知方法会在目标方法返回或者异常后执行
@AfterReturning 通知方法会在目标方法返回时执行
@Afterthrowing 通知方法会在目标方法抛出异常时执行
这里以一个返回正常的情况为例:(异常替换最后一步即可)
ControllerMethodLogAspect.class:用于打印日志的切面定义类
注意要在启动类扫描这个class,并且添加 @EnableAspectJAutoProxy(proxyTargetClass = true)
@Slf4j
@Component
@Aspect
public class ControllerMethodLogAspect {
@Pointcut("@annotation(com.xiyuan.demo.annotation.ControllerMethodLog)")
public void pointCut() {
}
/**
* 在切点运行前执行该方法
*/
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
ControllerMethodLog annotation = method.getAnnotation(ControllerMethodLog.class);
if (Objects.isNull(annotation)) {
return;
}
String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
log.info("start {}:入参:{}", methodName, JSON.toJSONString(joinPoint.getArgs()));
}
/**
* 在切点运行后,无异常时执行该方法
*
* @param joinPoint
* @param result
*/
@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturn(JoinPoint joinPoint, Object result) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
ControllerMethodLog annotation = method.getAnnotation(ControllerMethodLog.class);
if (Objects.isNull(annotation)) {
return;
}
String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
log.info("end {}:响应:{}", methodName, JSON.toJSONString(result));
}
}
验证
getUserById:根据id获取用户的信息
@GetMapping("/getUserById")
@ApiOperation(value = "根据用户id获取用户")
@ControllerMethodLog
public ResponseResult getUserById(@RequestParam(name = "id", required = true) String id) {
UserInfoPojo userInfoPojo = userService.getUserById(id);
return ResponseResult.success(userInfoPojo, ConstantsUtil.QUERY_SUCCESS);
}
Swagger接口信息如下:
IDEA控制台打印信息如下:
来源:https://blog.csdn.net/weixin_40990818/article/details/109039266


猜你喜欢
- Mybatis 入参方式单个基本类型或 String 参数在 mapper 文件中随便写<select id=""
- 本文实例为大家分享了java文件上传和预览实现代码,供大家参考,具体内容如下1、下载uploadify插件2、index.html<!
- Java 8的18个常用日期处理一、简介伴随lambda表达式、streams以及一系列小优化,Java 8 推出了全新的日期时间API。J
- 一、问题描述Android应用程序的四大组件中Activity、BroadcastReceiver、ContentProvider、Serv
- 先介绍下一些基本定义串行通信:通过的是PLC上的串行口RS232/RS422/485口,上位机链接系统 Hostlink系统是对于FA系统一
- IDEA全局替换通过快捷键 Ctrl+Shift+r 或这点击 Edit 》Find 》Replace In Path有些IDEA版本按了快
- 今天一直在绞尽脑汁的寻找解决两个字符之间的内容如何输出的问题,刚开始就使用了万能的正则表达式;但是不知哪里的原因自己的数据一直出不来,觉得应
- 一、项目搭建1、新建模块2、导入依赖 :将不相关的依赖删掉<!-- <de
- Java 执行 JS 脚本工具用途:为了便于系统扩展,提供了 JS 脚本的功能,可以通过在系统中执行脚本来获得更复杂的功能。例如:系统提供了
- Map接口Map类似y(x)=x;这样的函数(key对应x,value对应y)Map与Collection并列存在。用于保存具有映射关系的数
- 前言最近在刷java面试题偶然看到这类问题(try/finally中含有return时的执行顺序),觉得挺有意思于是小小的研究了一下,希望经
- 前言上一篇文章已经介绍了fluent-mybatis项目的构建,文章地址:Java Fluent Mybatis实战之构建项目与代码生成篇上
- RecyclerView的使用比ListView的使用是比较复杂的,ListView的使用是五个步骤,而我们的RecyclerView的使用
- 免责声明:本教程所有资源均来源于网络;仅用于学习交流,请勿用于任何商业行为;如需要,请使用正版授权;侵权联删。推荐最新 IntelliJ I
- 本文实例讲述了C#自定义处理xml数据类。分享给大家供大家参考。具体分析如下:这个C#类专门用户处理xml数据,可以大大简化xml的操作,类
- 1、创建Windows服务 说明:a)Description 服务描述,直接显示到Windows服务列表中的描述;b)Displa
- 程序分析: 兔子的规律为数列1,1,2,3,5,8,13,21....程序设计:public class exp2{ publi
- Java中IO的模型分为三种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。BIO【同步阻塞】在JDK1.4出来之前,我们建立网
- 我们都知道, Android EditText输入框,并没有监听用户输入完成的功能,需要我们自己实现。 下面是实现的方法,仅供参考:Edit
- 1.首先,八种基本数据类型分别是:int、short、float、double、long、boolean、byte、char; &