欢迎访问我的GitHub
https://github.com/zq2599/blog_demos
内容:所有原创文章分类和汇总,及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;
问题场景
本文是《K8S官方java客户端》的第二篇,在进入编码实战章节之前,有个问题需要大家有足够的了解,避免在后面的实战中耗费精力处理此类问题,来看看究竟是什么问题:
- SpringBoot是常用的应用框架,《K8S官方java客户端》系列的应用都是基于SpringBoot-2.3.1版本的;
- 下图是SpringBoot-2.3.1.RELEASE的官方文档,红框表明默认的JSON处理库是Jackson:
![90a02191bdf85ed94e52a9df96324311.png](https://i-blog.csdnimg.cn/blog_migrate/c61ebe00792d00593af5fa4d6b5cd0bb.jpeg)
- 看到这里您是否有种不祥预感:K8S官方java客户端是谷歌的,涉及到JSON处理时会不会首选自家的Gson?
- V1HTTPGetAction.java是java客户端中常用到的数据结构,用来封装http请求相关的参数,来看看其源码,如下图,果然用上了Gson的注解:
![2ef4bc0b59dd5f86e14cff17cc2de642.png](https://i-blog.csdnimg.cn/blog_migrate/dea6eab62cb8e44b3df9f11e5b132b22.jpeg)
- 上图提到的IntOrString类要重点关注,用处广泛,打开其源码如下图,请记下红框2中的代码,后面提到的问题就来源于此:
![0125bcf1a12ac479ed068cb43030a1ab.png](https://i-blog.csdnimg.cn/blog_migrate/7b01db8eaf759a3d6ccd4e2450f7d634.jpeg)
- 小结:SpringBoot默认的JSON处理类是Jackson,K8S官方java客户端内的Bean在涉及到JSON相关的序列化和反序列化处理时,使用了Gson注解,因此上述Bean实例在SpringBoot中涉及到JSON处理时,可能会有问题(这时只能说可能),例如RestController返回对象,会被Jackson转为JSON;
复现问题
- 这里用一个SpringBoot工程来演示此问题(该工程名为OutsideclusterApplication,下一篇文章会详细说明),如下代码是个http接口响应,可见V1PodList实例作为接口返回时,会被SpringBoot用Jackson转为JSON返回给前端:
@RequestMapping(value = "/hello") public V1PodList hello() throws Exception { // 存放K8S的config文件的全路径 String kubeConfigPath = "/Users/zhaoqin/temp/202007/05/config"; // 以config作为入参创建的client对象,可以访问到K8S的API Server ApiClient client = ClientBuilder .kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))) .build(); Configuration.setDefaultApiClient(client); CoreV1Api api = new CoreV1Api(); // 调用客户端API取得所有pod信息 V1PodList v1PodList = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null); return v1PodList; }
- 上述代码运行起来,在浏览器访问该接口时,控制台抛出以下错误,IntOrString.getStrValue方法,就是前面咱们看过的那段,IntOrString中实际上保存的是int数据,但是Jackson执行了其getStrValue方法:
![0e105dfde3e3d79398eebaa61a62380f.png](https://i-blog.csdnimg.cn/blog_migrate/e989222d30350049872a6e0b7d82edce.jpeg)
- 至于为什么Jackson会执行getStrValue方法,篇幅原因就不在此展开了,简单提一下,在java客户端的BeanPropertyWriter类中,选择方法的逻辑如下图,红框中展示了判定逻辑,此处getStrValue方法命中了该逻辑,如果您尝试用在红框处打上断点观察,会发现有很多方法都符合此条件:
![75517501c31f99215a8f78394f2b97bf.png](https://i-blog.csdnimg.cn/blog_migrate/d71d8736a7ed745ebabed4376fa8d2d3.jpeg)
解决问题的思路
我这里,解决问题的思路有两个:
- 让Jackson在序列化的时候,能够调用正确的方法,以IntOrString为例,如果此时内部保存int型数据,就应该执行其getIntValue方法即可;
- Bean中使用了Gson注释,就是打算用Gson来处理序列化和反序列化操作的,因此序列化和反序列化的地方都改用Gson处理;
- 上述两个思路,我选择了第二种,毕竟第一种太难了...
解决问题
- 问题解决起来并不难,先看SpringBoot-2.3.1.RELEASE官方文档:
![e00b42974755faf294cb593d32995197.png](https://i-blog.csdnimg.cn/blog_migrate/f848842caa18acfe79e4ef7a71c6e1d3.jpeg)
结合官方文档,我们要做两件事情:
- classpath中有Gson,这个已经有了,因为K8S官方java客户端会依赖Gson;
- classpath中不要出现Jackson,为了达到这个目的我们需要做以下操作,排除spring-boot-starter-web的依赖(为什么不直接排除jackson的库呢?您可以执行mvn dependency:tree命令细看依赖树,会发现对jackson的依赖并非单一关系):
org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-json
- 建议您执行mvn dependency:tree命令细看整个项目的依赖树,确保jackson依赖已经全部去掉;
- 再次运行上述项目,如下图,服务端不再报错,页面上返回数据正常:
![a2f55d54e58126ba828946f64e90e68e.png](https://i-blog.csdnimg.cn/blog_migrate/8e4e0ab777142580eb52e3cc6bac97d5.jpeg)
使用Jackson的场景
- 上述方式虽然可行,但并非所有项目都能坚持使用Gson而放弃Jackson,对于使用Jackson的项目,请避免Jackson参与K8S官方java客户端bean的序列化和反序列化操作,以上面出现的Controller代码为例,不要直接将V1PodList实例返回,您可以选择先用Gson序列化成JSON字符串,再返回字符串给前端,也可以自己定义VO对象,将V1PodList实例转成VO对象再返回;
至此,使用K8S官方java客户端之前要注意的问题已经弄明白了,接下来的进入精彩的实战章节吧,一起体验kubernetes官方为java程序员精心准备的工具;
欢迎关注我的公众号:程序员欣宸
![de672915f0e914f984a5ed2c66c3a07a.png](https://i-blog.csdnimg.cn/blog_migrate/ca0ca352f50285e08dcf1f0f6b6626cb.jpeg)