关于异常的方方面面

一. 业务中异常的处理

在开发业务代码的时候,异常是主流程之外的非正常流程,是主流程进行不下去的标志,是需要进行补偿处理的。
这里表述的异常,包括非正常的 http 状态码,和异构的外部系统返回的业务异常状态码。
针对这些异常, 站在完善流程的视角上,可以进行异常归类。

第一类是网络异常:针对这类异常,我们可以进行重试,但是要注意三方系统是否幂等,幂等接口可以重试。不幂等的接口,避免重复请求,造成资损,可以再请求一遍数据前校验一下状态。

第二类是业务异常:在网络顺畅的情况下,可能由于三方原因,有些流程进行不下去,这时,三方会返回状态码,标志是否请求成功,针对三方业务异常状态码,还可以进行一个归类。

  1. 需要人工介入的异常,这种异常无法判断是否成功,需要人工介入。
  2. 可以重试的异常,这种异常可能由于三方系统瞬时不可用,所以短时间无法成功,可以择机重试。
  3. 和三方系统失去信任异常。和三方系统进行交互式,可能需要账号、签名等校验,如果是校验失败,可以直接放弃并且此后不修改的话无须再请求三方系统,因为和三方系统之间交互的信任失去了。

基于上述分类,我们完善流程时,就有了多种条件,可以针对性的进行三方下架、重试、标记异常请求等。

如果是有多个相同能力的三方系统,还可以对三方系统的稳定性等进行打标,针对指标进行运营。

在写流程代码时,可以使用 微内核加插件化,平等对待第三方的设计思想。或者更进行一步,使用状态机进行流程编排,把固定的内核流程做成可以插拨的形式。

二. 虚拟机对异常的处理

首先 java.lang.Throwable 就是一个java类,没有什么特别的地方,之所以异常能够跳出链式调用流程,直接抛出,还是因为虚拟机的原因,因为 throw 关键字。

public static void main(String[] args) {
  try {
    mayThrowException();
  } catch (Exception e) {
    e.printStackTrace();
  }
}
// 对应的 Java 字节码
public static void main(java.lang.String[]);
  Code:
    0: invokestatic mayThrowException:()V
    3: goto 11
    6: astore_1
    7: aload_1
    8: invokevirtual java.lang.Exception.printStackTrace
   11: return
  Exception table:
    from  to target type
      0   3   6  Class java/lang/Exception  // 异常表条目
12345678910111213141516171819

附上一个编译后的带有 try catch 的字节码表,可以看出,编译后的字节码,每个方法都附带一个异常表,并且由 from、to、target 指针构成,这些指针的值,是 字节码索引。

from to 代表了监控的范围,targe 代表异常处理器的起始位置。

如果遍历完所有的一场表条目,仍未找到正确的异常处理器,那么会弹出当前方法的栈帧,并且在调用者中重复此操作。

虚拟机除了找到正常的异常处理流程外,还会构造生成该异常的栈轨迹。该操会逐一访问当前线程的 java 栈帧,并记录调试信息,包括 栈帧指向方法的名字、方法所在的类名、文件名、以及在代码中的第几行触发了该异常。所以异常实例的构建十分昂贵。

虚拟机异常其实就是同构系统对异常的处理。

三. rpc 中异常的处理

rpc 的基本流程 序列化-》网络传输-》反序列化。这是基本的流程,如果出现异常了,那么经过网络传输,然后经过反序列化,还会生成原来的对象吗?

Throwable 实现了 Serializable 接口,表明异常也是可以被序列化的。

不同的 rpc 框架有不同的处理方式。

dubbo 就是 com.alibaba.dubbo.rpc.filter.ExceptionFilter,这个类中对不同的异常有不同的处理方式,受检异常直接抛出,其他异常,原则上如果调用方是可以进行反序列化为 java对象 的就直接抛出,如果不能,则使用 RuntimeException 包裹后再抛出。

feign 默认是通过 http 协议进行网络传输。所以如果被调用方抛异常了,返回给调用方的,就不是异常对象,而是异常信息。springboot web 项目,异常时返回的信息就是 status、timestamp、message、error、path,仅通过这些信息,是没法反序列化成 java 对象的。所以 feign 的异常处理,是获取 message 信息,然后包装成 FeignException 返回出去。

因为 dubbo 框架抛出的异常信息中,有类信息,所以存在反序列化的可能。一般网络传输框架为了多语言通用,基本没有 java 的类信息,所以反序列化不回来。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值