SpringBoot通过自定义注解实现日志打印
目录
前言:
正文
一.Spring AOP
1.JDK动态代理
2.Cglib动态代理
使用AOP主要的应用场景:
SpringBoot通过自定义注解实现日志打印
一.Maven依赖
二.ControllerMethodLog.class自定义注解
三.Spring AOP切面方法的执行顺序
四.ControllerMethodLogAspect.class:用于打印日志的切面定义类
前言:
在我们日常的开发过程中通过打印详细的日志信息能够帮助我们很好地去发现开发过程中可能出现的Bug,特别是在开发Controller层的接口时,我们一般会打印出Request请求参数和Response响应结果,但是如果这些打印日志的代码相对而言还是比较重复的,那么我们可以通过什么样的方式来简化日志打印的代码呢?
正文
一.Spring AOP
Spring AOP 即面向切面,是对OOP面向对象的一种延伸。
AOP机制可以让开发者把业务流程中的通用功能抽取出来,单独编写功能代码。在业务流程执行过程中,Spring框架会根据业务流程要求,自动把独立编写的功能代码切入到流程的合适位置。
Spring AOP的实现方式
1.JDK动态代理
- 类对象必须实现接口
- JDK动态代理,背后是借助Java多态的特性,因为JDK动态代理生成的class文件已经继承了Proxy,而Java是单继承的,不能继承目标对象,只能实现目标对象(涉及向上转型),所以是基于JDK动态代理是基于接口的。
JDK动态代理主要涉及两个类:
- InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
- Proxy 利用 InvocationHandler 动态创建 一个符合某一接口的实例,生成目标类的代理对象。
2.Cglib动态代理
- Cglib是一个强大的高性能,高质量的代码生成类库, 可以在运行期扩展 Java 类与实现 Java 接口,CgLib 封装了asm,可以再运行期动态生成新 的 class。
特别要注意的是:
- 目标类实现接口的情况下使用JDK动态代理,没有实现接口的情况下使用Cglib动态代理。
- 可以使用ProxyTargetClass = true,强制所有都使用Cglib动态代理。
- Cglib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少,有研究表明,大概要高10倍;但是Cglib在创建对象的时候所花费的时间却比JDK动态代理要多很多,有研究表明,大概有8倍的差距;
- 对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用Cglib动态代理,反正,则比较适用JDK动态代理。
使用AOP主要的应用场景:
- Authentication 权限检查
- Caching 缓存
- Context passing 内容传递
- Error handling 错误处理
- Lazy loading 延迟加载
- Debugging 调试
- logging, tracing, profiling and monitoring日志记录,跟踪,优化,校准
- Performance optimization性能优化,效率检查
- Persistence 持久化
- Resource pooling资源池
- Synchronization同步
- Transactions 事务管理
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控制台打印信息如下:
相关文章:
SpringBoot通过自定义注解实现日志打印
目录 前言: 正文 一.Spring AOP 1.JDK动态代理 2.Cglib动态代理 使用AOP主要的应用场景: SpringBoot通过自定义注解实现日志打印 一.Maven依赖 二.ControllerMethodLog.class自定义注解 三.Spring AOP切面方法的执行顺序 四.ControllerMethodL…...
代码随想录算法训练营第七天 |151.翻转字符串里的单词
今天是代码随想录的第七天,写了力扣的151.翻转字符串里的单词; 之后或许还要再琢磨琢磨 代码随想录链接 力扣链接 151.翻转字符串里的单词,代码如下: # class Solution: # def reverseWords(self, s: str) -> str: # …...
【WebRTC---源码篇】(十:一)WEBRTC 发送视频RTP包
RTPSenderVideo在整个框架中起到重要的作用,它把采集的数据进行编码,并且在流程中会进行将编码后的数据进行RTP打包,最后发送到网络层 RTPSenderVideo::SendVideo //对编码数据打包 bool RTPSenderVideo::SendVideo(int payload_type,absl::optional<VideoCodecType>…...
cmd 90 validate error!(达梦数据库日志报错)
达梦数据库报错 error-cmd 90 validate error! 环境介绍1 解决办法 环境介绍 某生产环境数据库启动后,dm_实例名_202309.log,偶尔报错cmd 90 validate error! 1 解决办法 接口用错了,消息非法,比如用 6 的 JDBC 连 7 或 7 的 …...
Shape Completion Enabled Robotic Grasping
摘要-这项工作提供了一个架构,使机器人能够通过形状完成抓取规划。形状完成是通过使用3D卷积神经网络(CNN)来完成的。该网络是在我们自己的新的开源数据集上训练的,该数据集包含了从不同视角捕获的超过44万个3D样本。运行时,从单个视角捕获的…...
【C++】构造函数意义 ( 构造函数显式调用与隐式调用 | 构造函数替代方案 - 初始化函数 | 初始化函数缺陷 | 默认构造函数 )
文章目录 一、构造函数意义1、类的构造函数2、构造函数显式调用与隐式调用3、构造函数替代方案 - 初始化函数4、初始化函数缺陷5、默认构造函数6、代码示例 - 初始化函数无法及时调用 一、构造函数意义 1、类的构造函数 C 提供的 构造函数 和 析构函数 作为 类实例对象的 初始化…...
VMware16安装ghost版win7
文章目录 准备工作GHO 文件装机工具 新建虚拟机配置虚拟机还需要一个 CD/DVD PE 安装步骤分区还原挂载 CD/DVD开始还原 还原之后 准备工作 GHO 文件 可以去百度搜索这种文件,我这里是从系统之家下载的deepin win7 ghost 系统 装机工具 因为下载的 ghost 版的 w…...
项目集成swagger,访问不到swagger页面
项目集成swagger 文章目录 前言一、背景二、问题复现1.Full authentication is required to access this resource2.Illegal DefaultValue null for parameter type integer 总结 前言 项目集成swagger这个没啥好整的,maven项目就在pom文件导入依赖,ser…...
微信小程序怎么隐藏顶部导航栏(navigationBar)变透明的解决方案
怎么隐藏小程序顶部导航栏(navigationBar)? 官网说:Navigation是小程序的顶部导航组件,当页面配置 navigationStyle 设置为 custom 的时候可以使用此组件替代原生导航栏。 那么,我们就知道这种效果是可以…...
RabbitMQ基础概念-02
RabbitMQ是基于AMQP协议开发的一个MQ产品, 首先我们以Web管理页面为 入口,来了解下RabbitMQ的一些基础概念,这样我们后续才好针对这些基础概念 进行编程实战。 可以参照下图来理解RabbitMQ当中的基础概念: 虚拟主机 virtual hos…...
从构建者到设计者的低代码之路
低代码开发技术,是指无需编码或通过少量代码就可以快速生成应用程序的工具,一方面可降低企业应用开发人力成本和对专业软件人才的需求,另一方面可将原有数月甚至数年的开发时间成倍缩短,帮助企业实现降本增效、灵活迭代。那么&…...
Linux创建进程 及父子进程虚拟空间 多进程GDB调试
父子进程的资源是读时共享,写时拷贝,用到某一个资源,比如说改变变量的值的时候才去拷贝这个变量到一个独立的空间 父子进程的关系: 区别: 1.fork()函数的返回值不同 父进程中:>…...
uni-app 之 表格设置
uni-app 之 表格设置 image.png <view style"padding: 3%; border: #1296db;"><table style"width: 100%; border-collapse: collapse; "><tr style"height: 50px;border: 2px solid;border-color: #F7F7F7;"><td style&qu…...
Linux易混淆知识点
1. 使用 vi 编辑某个文件时,执行删除某行/某几行的操作: dd:删除光标所在行; 6dd:表示删除当前行开始 6 行数据。 ndd: 删除当前行开始的连续 n 行; n1,n2d:删除 n1 到 n2 行&#x…...
移植FlashDB、SFUD到STM32f407
个人上篇文章 搭建STM32F407的SPI-Flash(基于STM32CubeMX)_小刚学長的博客-CSDN博客 主要是解决STM32CubeMX这边的配置,对code端侧是简单介绍了下 实际项目上一般都是拿片外flash存储一些东西,比如一些比较多的配置、参数&…...
【算法基础】时间复杂度和空间复杂度
目录 1 算法的评价 2 算法复杂度 2.1 时间复杂度(Time Complexity) 2.1.1 如何计算时间复杂度: 2.1.2 常见的时间复杂度类别与示例 2.2 空间复杂度 2.2.1 如何计算空间复杂度 2.2.2 常见的空间复杂度与示例 3 时间复杂度和空间复杂度…...
解决微信小程序不支持TextEncoder/TextDecoder对象
问题描述:在使用小程序开发者工具开发小程序中使用到了CRC算法,其中有一行代码使用到了TextEncoder对象,在开发工具中一切正常,到手机上会报出错误错误如下: MiniProgramError TextEncoder is not defined ReferenceEr…...
Qt下SVG格式图片应用
SVG格式图片介绍 svg格式图片又称矢量图,该种格式的图片不同于png等格式的图片,采用的并不是位图的形式来组织图片,而是采用线条等组织图片,svg格式是图片的文件格式是xml,可以通过文件编译器打开查看svg格式内容。 …...
python异常处理
参考语法:https://docs.python.org/zh-cn/3/tutorial/errors.html 在编写代码的时候,如果你写的程序出现报错,程序就会停止运行,后面的代码就不再执行。 如果程序发生错误,可以在代码中添加异常处理,保证程…...
go get命令不再具有安装功能
go get功能呢 一直以来,我们知道go get命令可以借助代码管理工具通过远程拉取或更新代码包及其依赖包,并自动完成编译和安装。整个过程就像安装一个App一样简单。 go get命令可以动态获取远程代码包,命令在内部实际上分成了两步操作&#x…...
合宙Air724UG LuatOS-Air lvgl7-lvgl(矢量字体)
如何用开发板实现lvgl加载外部矢量字体功能 目录名称 如何用开发板实现lvgl加载外部矢量字体功能 简介材料准备API 说明步骤 1. 将字库芯片接在模块spi上2. 版本定制3. 初始化spi4. 设置字体5.字体使用测试固件和脚本显示效果字号灰度最佳粗细值对应表常见问题 1. 设置68号字体…...
LRU的实现
题目内容 实现一个 LRUCache 类,三个接口: LRUCache(int capacity) 创建一个大小为 capacity 的缓存get(int key) 从缓存中获取键为 key 的键值对的 valueput(int key, int value) 向缓存中添加键值对 (key, value) 要求 get 和 put 的均摊时间复杂度…...
consul 备份还原导入导出
正文 工作中要保证生产环境部署的consul的集群能够安全稳定地对外提供服务,即使出现系统故障也能快速恢复,这里将讲述部分的备份还原操作及KV的导入导出操作。 备份与还原 配置文件、服务器状态 需要备份的主要有两类数据:consul相关的配置文…...
6.网络编程套接字(下)
文章目录 4.TCP流套接字编程4.1ServerSocket API4.2Socket API4.3TCP中的长短连接4.4示例一:一发一收(长连接)4.4.1TCP服务端4.4.2TCP客户端 4.5示例二:请求响应(短连接)4.5.1TCP服务端4.5.2TCP客户端 4.6再…...
4.3-内置后置PostProcess处理器深度讲解
在reader里面注册了很多Bean定义 reader会调取register()来注册配置类 调用上句,就会把配置类注册到BeanDefinitionMap中去 配置类有了、解析配置类的处理器有了 然后, 在第三步refresh() 进行IOC容器刷新中的invokeBeanPostProcessors(beanFactory…...
LeetCode(力扣)45. 跳跃游戏 IIPython
LeetCode45. 跳跃游戏 II 题目链接代码 题目链接 https://leetcode.cn/problems/jump-game-ii/description/ 代码 class Solution:def jump(self, nums: List[int]) -> int:if len(nums) 1:return 0curdis 0nextdis 0step 0for i in range(len(nums)):nextdis max(…...
mysql5.8 免安装版(压缩包)win10 安装
目录 1、下载MySQL5.82、如何安装、配置my.ini配置注意 3初始化mysql3.1. 初始化mysql3.2. 安装mysql服务3.3. 启动mysql3.4. 登录mysql3.5. 修改root密码3.6. 配置远程连接 Mysql5.8安装踩坑记录,推荐使用Docker安装,我是电脑虚拟化可能会蓝屏没用这个功…...
STM32-HAL库06-硬件IIC驱动FM24CL16B非易失存储器
STM32-HAL库06-IIC驱动FM24CL16B非易失存储器 一、所用材料: STM32VGT6自制控制板 STM32CUBEMX(HAL库软件) MDK5 二、所学内容: 通过HAL库的硬件IIC对FM24CL16B存储器进行写与读取操作。 三、CUBEMX配置: 第一步…...
python-wordcloud词云
导入模块 from wordcloud import WordCloud import jieba import imageio import matplotlib.pyplot as plt from PIL import ImageGrab import numpy as npwordcloud以空格为分隔符号,来将文本分隔成单词 PIL pillow模块 img imageio.imread(image.png)这行代码…...
单元测试与自测
单元测试在百度百科的定义: 自测在百度百科的定义: 单元测试是测一个类或一个函数,自立门第main函数,不依赖于项目,预期的是这个类或函数是没有问题的。程序编码完成之后至各种测试再到用户使用出现的任何bug都是单元测…...
织梦dede新闻网站源码手机站/做优化关键词
有意义的命名 一.命名范围:变量,方法,参数,类名,包名;文件名,文件夹。 二.命名规则 1.名副其实:看到名字,就应该了解其代表的意义,其用途很自然地理解其功能。 2.避免…...
网页设计实验报告结果/优化大师win10
本文中概述的一些准则可以被客观地评价;其他的,则是有场景的、上下文环境的或主观的。 最重要的一点,是保持一致性。 一致性的代码更容易维护,更容易优化,需要更少的学习成本,并且随着新约定的出现或bug类的修复&…...
做lol数据的网站/营业推广策略有哪些
时间过得真快。一转眼时间,我们有进入到了第二阶段的学习。让我感到欣慰的是,传说中的jquery开始学习了。还有就是我们的导师也换了! 两天的学习让我感觉还是挺轻松的。感觉jquery和JS比起来,真的是天壤之别!而学习起来…...
游戏网站策划书/优化大师的作用
data data.div(data.sum(axis1), axis0)data.sum(axis1) 表示按行求和data.div(sum_data,axis0) 表示按行除...
佛山企业网站开发/傻瓜式自助建站系统
一、分析 一般来说,我们经常使用的枚举项只有一个属性,即排序号,其默认值是从0、1、2... ...。但是除了排序号外,枚举还有一个(或多个)属性。 二、场景 比如,可以通过枚举构造函数声明业务值&am…...
php程序员网站开发建设/b2b网站平台有哪些
我写过一些开源项目,在开源方面有一些经验,最近开到了阮老师的微博,深有感触,现在一个开源项目涉及的东西确实挺多的,特别是对于新手来说非常不友好 最近我写了一个jslib-base,旨在从多方面快速帮大家搭建一…...