- 由于篇幅过长,将该模块单独拎出一节,接上文Hmily 源码解析(二)
- 前面我们执行完了Hmily切面的前置操作,现在要执行主体方法了
- 首先第一步就是将Order实例存储到数据库中,这一步就是对order表执行了try操作,这是我们的第一个try操作
- 第二步执行扣减库存操作,inventoryClient.decrease方法是fegin接口,且拥有@Hmily注解,说明我们又要进入Hmily的切面类了。
- 进入切面,对应上文的 SpringCloudHmilyTransactionInterceptor.interceptor方法
- 这次HmilyTransactionContextLocal中有存储HmilyTransactionContext实例,当前的状态也是start,所以被修改为了SPRING_CLOUD。
- 进入invoke方法–>factoryOf方法,根据当前角色spring_cloud,角色又被改回了start,并且返回ConsumeHmilyTransactionHandler.class对象,这次分流我们将要走ConsumeHmilyTransactionHandler实例的handler方法
- ConsumeHmilyTransactionHandler实例的handler方法内部只执行主体方法,也就是通过fegin调用其他微服务,而没有其他额外的操作。
- 这边我们可以了解到在这个切面里没有做任何额外的操作,仅仅只是执行了主体方法,也就是调用fegin接口
- 现在我来看一下feign接口做了什么。。。。
feign 配置解析
- HmilyFeignConfiguration 是一个配置文件
- feign配置文件里面一共有三个配置(PS:这个配置文件好像并没有指明只用于feign,所以默认是对所有的生效)
- 先来第一个配置HmilyFeignInterceptor,这是一个http的拦截器配置,它的作用是将当前的线程的HmilyTransactionContext实例以“HMILY_TRANSACTION_CONTEXT”为key作为请求参数存储到请求头里面(header)发送给其它微服务。
- 这就是多个微服务之间进行分布式事务消息的传递,但是很明显这个传递只是由上至下的单向传递消息。
- 刚才说了这个配置好像不只是对fegin的请求生效,而且也没有做什么特殊的过滤,这岂不是所有的请求都会加一下这个请求头??!!
- 我们看第二个配置,HmilyFeignBeanPostProcessor是spring的bean生成处理器,重写了postProcessAfterInitialization方法,它的作用是在spring 将bean生成之后做自定义的处理。
- 如下代码,先看第一个if,它的作用是过滤所有非代理类的,就是对非代理类不做处理。什么是代理类?我们写的feigen接口就是feign帮我们实现(代理)的。
- 再往下,对于feign中有加@Hmily注解的实例,改为使用动态代理的方案去调用该实例。但是HmilyFeignHandler代替了原生的InvocationHandler实例作为参数传入。
- InvocationHandler的作用是:代理时是调用该类的invoke方法来实现调用被代理的方法,这里采用自定义HmilyFeignHandler的意思就是想在调用方法前后作一些特殊处理。
- 所以这个方法的作用就很清楚了,对feign接口且有@Hmily注解的类添加代理调用。
- 我们继续深入一下HmilyFeignHandler的invoke方法做了什么。
-
invoke方法里面我们只需要看红色框里面的代码,这是被加了@Hmily注解的方法被处理时要做的处理,我们一一看一下,首先我们的角色是START,所以第一个if内role状态不会被改变为INLINE。
-
然后通过调用delegate.invoke方法调用原来的方法,也就是调用feign接口(给其它微服务发起try请求)
-
如果请求没问题则生成HmilyParticipant实例,通过hmilyTransactionExecutor实例发布HmilyParticipant实例,也就是异步存储到HmilyTransaction实例中的hmilyParticipants的集合中。
-
如果在发布之前报出异常的话,则抛出异常说明try失败。
-
所以这个配置文件做了什么?给有@Hmily注解的feign接口加了一个动态代理,以实现在调用该方法时,把该接口方法封装为HmilyParticipant实例异步存储到存储到HmilyTransaction实例中。
-
第三个配置hystrixConcurrencyStrategy,hystrix是熔断处理框架,就是在调用微服务的时候如果出现超时或者其他异常时,可以通过hystrix设置处理方案。但是有一个小问题hystrix允许单独开启一个线程去处理熔断方法,那就会导致新的线程里面不存在与分布式事务相关的信息(HmilyTransactionContext实例),以上。我们看一下hystrixConcurrencyStrategy的代码,也就这一块代码同我们的业务相关,如下做了什么,把HmilyTransactionContext实例从HmilyTransactionContextLocal取了出来,又存放到HmilyTransactionContextLocal中去(这就是另一个线程了),从而保证了在该线程内也能获取到当前的事务信息。
-
另外好像在demo中并没有去做熔断处理??只是建了两个类InventoryHystrix与AccountHystrix,但是并没有被使用,毕竟如果使用了熔断方法里面不抛出异常那发起者那边就会继续去执行confirm命令而不是执行cancel命令了,那就有问题了。是这样的吧?没用到,对!没用到。
-
第三步是扣除账户余额的操作,同第二步异曲同工这边就不复述了。