使用Feign远程调用时,序列化对象失败的解决
Feign远程调用序列化对象失败
最近在搭建一个SpringCloud的微服务时,遇到了一个问题,在使用Feign远程调用时报错,返回对象没有无参构造方法,有其他的含参数的构造方法。
本地自己搭建的微服务目录大概如下,才刚开始,后续会逐渐补充优化迭代,有兴趣的可以fork下地址:
https://github.com/zhanghailang123/MyCloud
给与指导意见。
Eureka
:注册中心服务端,采用Eureka注册中心EurekaClientA
:其中的一个Eureka服务端,命名有点随意,相当于一个数据提供中心,暂时没有使用ORM框架对接数据库,把相应数据写死了,目前只是在练习使用为了方便,后续考虑使用SpringJPA,因为Mb用的太多了FeignZ
:feign模块远程调用加负载均衡,而且整合了Hystrix熔断机制,当然目前只做了最简单的Demo,练习下手感HystrixDashboard
:Hystrix仪表盘,可以关注下当前的服务器状况
RibbonZ
:主要用作于负载均衡,启动时可以启动EurekaClientA 多次指定不同的端口号,来测试下负载均衡,一般都是用Feign直接远程调用,内置了ribbon,这个demo中也是为了测试用的。TurBineZ
:用来监控集群的熔断情况。ZuulZ
:网关
接下来进入正题。
场景: 在使用Feign远程调用写死的数据服务EurekaClientA时,报错如下
feign模块如下:
此处为了复现问题,将熔断逻辑暂时注释掉
此处报错信息:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.example.pojo.Student` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
报错的对象 :org.example.pojo.Student 如下,一个很简单的bean对象:
那为什么会报这个问题呢 :不存在无参构造函数,序列化失败
带着疑问走进报错的地方:
可以看到是这个地方 canInstantiate()方法校验没通过。在此处打个断点一探究竟
这个校验里面内容是:
总之都是校验无参构造函数。如果给调用的student对象加上无参构造函数就可以成功调用。
构造函数就可以成功调用。**
问题倒不是什么大问题,在搭建服务过程中,只有亲力亲为,切实参与到了,才能感受到各种奇奇怪怪的小问题,也只有这样自己亲自动手,才是收获最大的。
Feign做远程调用的注意点
在使用feign的过程中遇到了一些问题,所以在这里做以下总结
1.定义的做远程调用的api接口
中的方法参数列表中的参数都必须都要打上@RequestParam(“value”) 注解**,否则调用会报405异常,这一点是和controller中不一样的,controller中的方法只要参数名和前台传入的参数键名对应上就能自动绑定上参数
复杂类型用必须打上@RequestBody注解
2.service微服务中的Controller的参数绑定
如果参数列表中有复杂类型,请使用Post请求,使用Get请求会报Bad Request错误,且需要打上@RequestBody注解,而普通基本类型可以不用打上@RequestParam注解可自动绑定参数
如有其它问题,也欢迎补充,放一下代码:
api:
@FeignClient("MS-ADMIN-SERVICE") public interface FixFeignService { @GetMapping("/fix") public List<FixInfo> findAll(); @PostMapping("/fix/add") public int insert(@RequestBody FixInfo fixInfo); @PostMapping("/fix/limitByParam") public LayUIPageBean limitByParam(@RequestBody FixInfo fixInfo, @RequestParam("page") Integer page, @RequestParam("limit") Integer limit); @PostMapping("/fix/delByIds") public boolean delByIds(@RequestParam("ids[]") Long[] ids); @GetMapping("/fix/findById") public FixInfo findById(@RequestParam("id") Long id); @PostMapping("/fix/update") boolean update(@RequestBody FixInfo fixInfo); }
service微服务
@RestController @RequestMapping("/fix") @Slf4j public class FixInfoController { @Autowired private FixInfoService fixInfoService; @GetMapping("") public List<FixInfo> findAll(){ List<FixInfo> all = fixInfoService.findAll(); return all; } @PostMapping("/add") public int insert(@RequestBody FixInfo fixInfo){ return fixInfoService.insert(fixInfo); } @PostMapping("/limitByParam") public LayUIPageBean limitByParam(@RequestBody FixInfo fixInfo,Integer page,Integer limit){ LayUIPageBean layUIPageBean = new LayUIPageBean(); PageHelper.startPage(page,limit); List<FixInfo> all = fixInfoService.findByParam(fixInfo); PageInfo<FixInfo> pageInfo = new PageInfo<>(all); return layUIPageBean.setCount((int)pageInfo.getTotal()).setData(pageInfo.getList()); } @PostMapping("/delByIds") public boolean delByIds(@RequestParam("ids[]") Long[] ids){ //log.info("id"+ids[0]); boolean flag= fixInfoService.delByIds(ids); return flag; } @GetMapping("/findById") public FixInfo findById(Long id){ return fixInfoService.findById(id); } @PostMapping("/update") public boolean update(@RequestBody FixInfo fixInfo){ return fixInfoService.update(fixInfo); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。