Spring Cloud用OpenFeign做远程调用的话要注意返回值类型能不能被反序列化

每次从零开发一个服务的时候总是遇到各种各样奇怪的问题,今天又从Spring Initializr开始开发一个服务。抄自己的不算抄,本着CV大法优先的原则,从之前其他项目中拷贝了几个component,比如响应Entity封装的类型啊,自定义异常枚举啊这些,如图:

坏就坏在这些不是从Spring Cloud项目中拷过来的,浑然不知已经埋下了坑还嘻嘻哈哈地写了一个client,就是一个简单的用OpenFeign调用一个远程服务,如图:

可以看到这里给响应Entity封装了一个HikResponse类型,而这个类就是上面拷贝过来的。服务一起方法一调用,报错了......

错误信息如下:

报错倒是挺明白的,说不能构造HikResponse,是因为没有默认构造器,也就是无参构造器。因为项目中用了lombok,原先HikResponse是这样的:

确实没有无参构造器,那就加一个无参构造器就是了,如下:

这样问题确实解决了!但是好奇心想让我找出根本原因。

根据异常栈信息可以定位出是哪一行报的错,即DeserializationContext.handleMissingInstantiator()方法,在报错的地方打了一个断点:

看来是valueInst.canInstantiate()这个方法没有校验通过,通过断点信息可以看到这个valueInst的类型其实就是HikResponse,那也就对上了,就是这个HikResponse不能被实例,可以看看这个canInstantiate()方法,看看什么才能算是能够被实例化:

反正都是无参的,第一个就是有默认构造器。

源码看到这里我还是有点疑惑,脑子里想到了之前用的HttpClient,同样都是调用远程服务的接口,为啥HttpClient没有出现这个问题呢,看了一下以前写的HttpClient代码:

其实我们用httpClient.execute()执行调用请求的时候,返回值直接就是Response,这个时候响应还没有被解析,是需要我们自己去解析的,而我们一般都是用InputStream去解析。

但是OpenFeign不是,OpenFeign调用远程服务,我们调用的方法返回值直接就是解析好的对象,例如这里就是ResponseEntity<HikResponse>,从二进制到对象,那这就必然涉及到一个反序列化的过程,反序列化的过程中是需要类可以被实例化,也就是刚刚的canInstantiate()方法。

这样就串起来理解了,最后可以通过贴源码的方式看一下OpenFeign调用远程服务的过程,加深一下理解:

从excutedAndDecode()方法开始看,这里算是开始调用远程服务了,template就是远程服务的地址,可以看出路由还是服务名,说明还没有经过负载均衡到具体的服务节点,options就是请求的一下参数,比如超时时间等。看excutedAndDecode()方法:

这里的this.client.execute()是真的开始调用远程服务了,可以看到这个this.client的实例是LoadBalancerFeignClient,它是org.springframework.cloud.openfeign.ribbon包里面的,说明这里的负载均衡是用的ribbon。其实有两种负载均衡的实现,可以看一下这个继承关系图:

 而另一个FeignBlockingLoadBalancerClient是在org.springframework.cloud.openfeign.loadbalancer包里面的,这是两种负载均衡的实现,关于loadbalancer和ribbon的比较可以参考这篇博客(https://blog.csdn.net/qq_16063307/article/details/99937060)。继续往下看,这里execute后是拿到响应Response了,然后开始handleResponse(),看一下这个方法:

 就是这里,开始对响应反序列化了,是一个二进制到对象的过程,需要类可以被实例化,然后就到了最初报错的地方,之后的代码就不截图了。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值