AOP+MybatisPlus 优化特殊的日志模块

简单思考

我们可以发现这些这些东西和业务无关,可以直接用 AOP 来实现,老项目中也是用了 AOP。(听君一席话,听君一席话 哈哈哈 🤣)

先简单思考下会遇到什么问题 👇

比如:

  1. 新增数据到相应的 log 表,意味着有很多简单的插入语句要写?还要考虑批量操作 🐖

  2. 操作id 是怎么生成的?是直接用 uuid ,还是数据库自增id?

  3. 怎么获取删除前的数据信息 、更新后的数据、插入后的数据 等

这里就不卖关子啦 直接来看这个日志模块的设计

操作ID

先来看这个 操作 ID 的生成,这里就没啥特别的  直接定义一个 注解  如 @GenerateRequestID ,加在需要被拦截的方法上,然后我们在 AOP 中拦截它即可。功能如下 👇

f6fd5f82a3af4e9d74d10c1c04a3e8cd.png

image

可以看到这个 操作ID 是直接使用 Oracle 的 Sequence 去生成的,是有序的 ,能直接看出这批数据操作的先后顺序。

在增强这部分功能时,我发现之前 旧版本居然没用 AOP 去设置这个 操作ID,而是手动在需要的地方加,而且还定义了很多的 Key 来存储生成的这个 操作ID,可以发现对这个 ThreadLocal 也很不熟悉呀!🙃

伪代码如下 😱 (坏代码 …… )

public void a() {

BigDecimal transactionId = sysLogMapper.generateTransactionId();

ThreadLocalUtil.setValue(SysLogConstants.xxx_LOG_TRANSACTION_ID, transactionId);

ThreadLocalUtil.setValue(SysLogConstants.aaa_LOG_TRANSACTION_ID, transactionId);

// 业务方法

ThreadLocalUtil.remove(SysLogConstants.xxx_LOG_TRANSACTION_ID);

ThreadLocalUtil.remove(SysLogConstants.aaa_LOG_TRANSACTION_ID);

}

心细的小伙伴会不会有个小疑问,为什么我是在 请求结束 时才去清除这个 操作ID,而不是在 AOP 的 After 操作中去做的😄

其实这里是有个小插曲的,一开始我是在 AOP 的 @After 操作中去删除这个 操作ID 的,但是呢 🙄 ,有同事将我改好的日志模块中的部分功能添加到之前的老项目中,而且他直接将这个注解加在 service上,结果系统出现了bug 🙄,还把我拉过去讨论 😒 ,这就很无语了……

11f7592892e125bf01ad1241c0c80c28.png

image

不过这个 bug 是不难发现的,毕竟这个注解如果加在 service 层面,会存在 service 调用 service 的情况,这样不仅会出现第一个 service 中生成的 操作ID 被第二个 service 覆盖,而且在第二个 service 结束后,操作ID 会被清除掉,但是这个字段是不允许为 null 的,所以就报错了。

按理说,直接加在这个 controller 层面就没问题了,但是讨论过后,在同事的建议下,我也同意对它进行小小的升级下,将这个 清除操作ID 的行为移动到这个 拦截器 中  👇

@Component

public class ThreadLocalInterceptor implements HandlerInterceptor {

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

ThreadLocalUtil.clear();

}

}

感觉这种方式也挺简洁的,在请求结束后直接清掉这个 ThreadLocal 中的内容。🐖

整体设计

接着,我们来看看这个 datalog 的生成。新版的整体思路如下。😋 (画出来清晰多了)

235725b3722a9c1909ecef9af121e396.png

2021-11-12_140557

删除操作

思路如上图~

在删除成功时,要将被删除的数据写到 Log 表 …… 😑

这里有两种情况:(一)根据主键删除 ,这种最简单,我们直接根据主键查出之前的数据即可。(二)根据其他条件删除,这里我们自定义获取主键的方法以便复用上面的方法。

这里就不得不提下这个 MybatisPlus 的好处了~ ,借用 BaseMapper 的 selectBatchIds 方法,我们可以很轻松的

查询出这些数据出来。

4e48231a39e2c8dabf945851f151d871.png

image-20211112142253855

因为在使用 MybatisPlus 时,我们会生成相应的 Mapper 方法,而这里就很好地体现了  Java 多态 的特点,我们只需要调用  (BaseMapper) SpringUtil.getBean(XXXMapper.class).selectBatchIds(result) ;即可实现。😄

所以将这个参数挂在 @MethodLog 注解上即可。

@Mapper

public interface XXXMapper extends BaseMapper {

}

而在旧版本中,由于没有用到 MybatisPlus ,自然写了很多的 删除语句 😱

而且由于对这个 Spring 的理解不够,出现了把 实现了同一个接口的不同子类注入到一个Map中,使用时再从其中获取的行为,最要命的是,这个 map 的key 不是那些子类的名称,还写了很多 switch case …… 😶 来获取

2982fab3a443980d666910bdfe278ae8.png

image-20211112221843944

其实我们直接用 ApplicationContext 的 getBean 就可以获取到了 🐖

更新,插入操作

在更新或者插入成功后,还要将这些数据写到 Log 表 …… 😑

真是太魔幻了……   再坚持下就快到吐槽环节了😂

这里我们要考虑一个问题了—— 插入数据时,ID 是插入数据前就有的,还是插入数据后才有的?🐷

在项目中我们使用的是这个 Oracle,借助它的 Sequence,我们可以先获取这个 ID  (select XX_SEQ.nextval from dual),再设置到这个对象中去,然后再插入 DB 中 。

而在使用 MySQL 时,我们一般都是通过数据库的自增ID,当数据插入后,再从这个对象中获取到这个 ID 的。

这也决定了我是在 AOP 的 Before 中记录下这些 ID ,还是在 AfterReturning 中去获取的。

其实一开始我是直接在 Before 中去记录的,后来考虑到这种情况后,才把它移到 AfterReturning 中去的,毕竟不管你先生成还是后生成,我都可以后获取,而且第二种模式兼容第一种模式 🐷

更新的话也有两种情况:(一)根据主键更新 ,这种最简单,我们直接根据主键查出之前的数据即可。(二)根据其他条件更新,这里我们自定义获取主键的方法以便复用上面的方法。

一般情况下,我们可以自动去获取这个 id,有些情况比较复杂的,就提供这个手动模式,自己调用 ThreadLocal 并耦合到代码中。

最后使用 Spring 的工具 BeanUtils ,将数据拷贝到日志对象中 BeanUtils.copyProperties(model, logModel); ,再通过 BaseMapper 的 insert 方法,将数据一条条插入到 Log表。

到此,就完成了这个特殊的日志模块的优化了。

e4365d05c5d90f74a940a91cc293a71a.png

image-20211112222053399

这个模块也为团队节省了 N 倍的开发时间,减少了很多冗余,无效的代码,也提高了这个代码的可维护性,受到同事的肯定当时 哈哈 😝 而且好像从这时候开始,老大找我做了一些通用模块的开发,比如 模板,邮件,Excel 等,有机会再来和小伙伴们分享下~ 😄。


吐槽

终于来到这里了,说实话,我到现在都觉得这个日志模块很 “特别” 🐷,因为这个日志模块不像我平时了解过的那些,比如:

最后的话

无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。
同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,好了希望这篇文章对大家有帮助!

部分截图:
在这里插入图片描述

找小编(vip1024c)领取

吐槽

终于来到这里了,说实话,我到现在都觉得这个日志模块很 “特别” 🐷,因为这个日志模块不像我平时了解过的那些,比如:

最后的话

无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。
同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,好了希望这篇文章对大家有帮助!

部分截图:
[外链图片转存中…(img-V2bs8lXj-1721629395808)]

找小编(vip1024c)领取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值