大家好,又见面了,我是你们的朋友全栈君。
- 由于篇幅过长,将该模块单独拎出一节,接上文Hmily 源码解析(二)—— 执行主体方法
- 上文我们把主体方法的执行及Feign的相关配置讲解了,知道在调用微服务时把对应的HmilyTransactionContext实例以“HMILY_TRANSACTION_CONTEXT”为key作为请求参数一同发送过来,及调用微服务成功之后会把调用接口的方法(有@Hmily注解的)封装为HmilyParticipant实例异步存储到存储到HmilyTransaction实例中。
- 现在接着讲在库存微服务接收到请求后会如何执行请求并做了哪些操作。
- 如下请求调用一开就需要先进入Hmily切面程序
- 根据前文,前面的类不再重复介绍,现在执行到了interceptor方法,首先这个请求刚开始,这个线程内还未存在HmilyTransactionContext实例。所以到下面这个else模块,这里很重要,我们记得前面在请求头里面有存在“HMILY_TRANSACTION_CONTEXT”为key的HmilyTransactionContext实例信息,现在就从这里取出来了。致此我们了解了微服务间是如何实现关于事务信息的通信。
- 我们现在来看一下factoryof方法里面是如何选择处理类的,传过来的角色为发起者(HmilyRoleEnum.START)所以选择了ParticipantHmilyTransactionHandler去执行后续操作。
- 目前我们的状态是TRYING 所以我们目前只要关注红色框内的代码即可
- 先看一下preTryParticipant内做了什么,首先新建了一个HmilyTransaction实例,这个实例是存储在hmily_inventory_service表中的,和前一个HmilyTransaction实例不是同一个实例了。
- buildHmilyTransaction函数前面讲过,根据参数的不同,新建的这个HmilyTransaction实例的角色为提供者(PROVIDER),transId为传入的transId,运行状态为开始执行try阶段(PRE_TRY),其它的类信息,HmilyParticipant实例信息是从本次切面对象(decrease函数及对应的Hmily注解信息)上获取的。目前HmilyParticipant只有decrease函数本身。
- 将生成的HmilyTransaction实例存储到缓存里(缓存和线程就无关了,而是以transId为key存储,只要在有效时间内都能获取得到),及异步保存到hmily_inventory_service表中。
- HmilyTransactionContext将角色改为本地调用( LOCAL),又一个角色状态现在被使用了!而且HmilyTransaction实例并没有一起被修改,而微服务的调用者的角色状态也仍是发起者(START),大体可以猜测本地调用( LOCAL)可能是个中间状态,在这次使用完之后就会丢弃。
- 然后HmilyTransactionContext绑定到本地线程。
- preTry之后第一步执行主体方法,主体方法内部非常简单,就是一条数据库操作就不再述了,接着如果执行主体方法成功没问题,则修改执行状态为try完成(TRYING),并异步保存到数据库中。如果执行失败报出异常则发起请求异步删除hmilyTransaction实例,并向上继续抛出异常(抛给微服务调用者),再往下finally里就是线程结束时的收尾工作,不再复述了。
- 微服务的try阶段就完成了,之前说的本地调用( LOCAL)状态好像没用到,的确demo里没有覆盖这么全面,没有案例我也先不去分析了。
- 我们可以再简单介绍一下CONFIRMING,与CANCELING的情况,当微服务第二次接收到请求时,状态就会变成CONFIRMING或者CANCELING。
- 首先他们的第一步都是通过transId从缓存中获取HmilyTransaction实例。
- 为什么要这样做,不直接从数据库获取HmilyTransaction实例?我猜测是这样的,上文异步保存HmilyTransaction实例到数据库与第二次请求的时间之间谁快谁慢这是说不准的,有可能第二次请求已经来了,但是数据库中还未保存HmilyTransaction实例,如果这时候去数据库中去可能就会返回null。在缓存中存储一个HmilyTransaction实例就可以解决这个问题,如果第二次请求更快则直接取缓存数据,反之第二次请求由于某些原因特别慢导致缓存已经失效了,但是这时间足以保证HmilyTransaction实例保存到数据中,这时依然能够通过HmilyTransactionGuavaCacheManager从数据库中获取该实例(见GuavaCache的获取机制)。
- 接着就是根据HmilyTransaction实例执行对应confirm方法或cancel方法。
- 我们看一下confirm方法做了什么,cancel方法类似就不分析了
- 1.修改状态为CONFIRM阶段(CONFIRMING)
- 2.前文说了,hmilyParticipant实例只有一个就是decrease函数本身,如何通过反射调用Hmily注解里面配置的confirm方法(confirmMethod)。如果有执行失败的hmilyParticipant会存储在failList集合里面。
- 3.,然后执行executeHandler函数,如下二图,成功删除相应的HmilyTransaction实例信息,如果有失败案例,则异步修改HmilyTransaction实例的hmilyParticipants集合(只保留执行失败的hmilyParticipant集合),后面定时器会再根据日志去定时执行这些hmilyParticipants集合,直到所有的hmilyParticipant被正确处理,或超过执行重试次数报个管理员手工处理。关于定时器重试执行的内容这边先按下不表。
- 对于这个demo的情况就是,hmilyParticipants集合里只有一个hmilyParticipant实例,如果confirm失败了,就通过定时器不停的重试执行,cancel失败如是,直到超过最大重试次数。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/143269.html原文链接:https://javaforall.cn