使⽤Feign远程调⽤时,序列化对象失败的解决
Feign远程调⽤序列化对象失败
最近在搭建⼀个SpringCloud的微服务时,遇到了⼀个问题,在使⽤Feign远程调⽤时报错,返回对象没有⽆参构造⽅法,有其他的含参数的构造⽅法。
本地⾃⼰搭建的微服务⽬录⼤概如下,才刚开始,后续会逐渐补充优化迭代,有兴趣的可以fork下地址:
给与指导意见。
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.InvalidDefinitionException: Cannot construct instance of `ample.pojo.Student` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
报错的对象:ample.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((Total()).List());
}
@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);
layui框架怎么用
}
}
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。