正在公司摸鱼的我突然接到了大佬给我的一个人任务,开发一个日志注解,来记录当方法中的每一个参数的名字,并记录每次的参数修改的值信息。接到任务的我瑟瑟发抖。
1. 数据库选择MongoDb
因为MongoDb具有以下特点
- MongoDb为文档型数据库。操作起来比较简单和容易。
- Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
- MongoDb采用Bson(类json的一种二进制形式的存储格式)存储数据,跟新和查询的速度很快
当然了MongoDb还有很多优点我就不一一赘述了,大家可以去官网看看文档。
2. 开发实体类保存到数据库中
1 | typescript复制代码@Data |
- 在数据库中保存的数据格式大体是这样的
3. 思考问题
当时我在做这一个功能的时候在想,你无法确定方法的入参到底是什么类型,有可能为实体类型,有可能为Map类型,有可能为String类型,如果参数为实体类型的需要去进行反射获取其中的所有字段,这是一个很耗时的操作,那么我为什么不拿出来在SpringBoot初始化的时候来做这个事情呢,于是就有了下面的操作。
- 首先创建一个实体类用来保存当前方法中的
参数名
,参数类型
,字段值
,和当前字段值对应的具体位置
1 | ruby复制代码@Data |
- 开发日志注解,
1 | less复制代码@Target(ElementType.METHOD) |
1 | arduino复制代码public enum LogTypeEnum { |
- 将实体类需要保存的字段进行细分,于是便又开发了一个注解,用来确定实体类中具体需要把那些字段信息保存到日志中
1 | less复制代码@Retention(RetentionPolicy.RUNTIME) |
- 在Springboot进行初始化的时候把方法中的参数进行缓存,若参数为实体类,进行反射获取其中所有的字段属性
1 | ini复制代码@Component |
用监听的方式监听WebServerInitializedEvent
在启动的时候做缓存,RequestMappingHandlerMapping
可以获取所有Controllec层标注@RequestMapping
的方法
4. 用Aop来保存参数内容
- 可以用spel表达式加入到注解中,这样就可以在aop中去解析获取关键值,可以参考 juejin.cn/post/684490… 篇文章
- 为了免去使用if和else来判断参数类型我使用了适配器模式,并把每一个参数类的解析抽出取来,这样当你添加不同参数类型的解析的时候可以避免代码的侵入性
- 下面是一个类型判断的接口,可以判断当前参数的类型,并且去调用当前参数类型的解析器
1 | typescript复制代码public interface TypeAdapter { |
- 这是map的类型判断并且实现map类型的参数解析
1 | typescript复制代码@Component |
- 下面是一个参数类型的解析接口
1 | typescript复制代码public interface ContentParse { |
- 参数类型解析接口的实现
1 | scss复制代码@Component("classParse") |
- 之后我们就可以写一个Util类用来获取数据库中根据当前类路径跟方法名所对应的参数值,并跟当前传的新值作比较,判断那个参数的值有修改
1 | typescript复制代码@Component |
- 接下来就是在aop中使用这个util工具
1 | scss复制代码@Slf4j |
5. 小结
- 作为一个刚入门半年的菜鸟我还是又很多地方需要学习,这个方法肯定还能在进一步的优化,希望各位大佬能给指点一下。希望大家共同进步。
本文转载自: 掘金