写点什么

Kubernetes 官方 java 客户端之二:序列化和反序列化问题

作者:程序员欣宸
  • 2022 年 3 月 31 日
  • 本文字数:2057 字

    阅读完需:约 7 分钟

Kubernetes官方java客户端之二:序列化和反序列化问题

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


问题场景

  • 本文是《Kubernetes 官方 java 客户端》的第二篇,在进入编码实战章节之前,有个问题需要大家有足够的了解,避免在后面的实战中耗费精力处理此类问题,来看看究竟是什么问题:

  1. SpringBoot 是常用的应用框架,《Kubernetes 官方 java 客户端》系列的应用都是基于 SpringBoot-2.3.1 版本的;

  2. 下图是 SpringBoot-2.3.1.RELEASE 的官方文档,红框表明默认的 JSON 处理库是 Jackson:


  1. 看到这里您是否有种不祥预感:K8S 官方 java 客户端是谷歌的,涉及到 JSON 处理时会不会首选自家的 Gson?

  2. V1HTTPGetAction.java 是 java 客户端中常用到的数据结构,用来封装 http 请求相关的参数,来看看其源码,如下图,果然用上了 Gson 的注解:



5. 上图提到的 IntOrString 类要重点关注,用处广泛,打开其源码如下图,请记下红框 2 中的代码,后面提到的问题就来源于此:


  • 小结:SpringBoot 默认的 JSON 处理类是 Jackson,K8S 官方 java 客户端内的 Bean 在涉及到 JSON 相关的序列化和反序列化处理时,使用了 Gson 注解,因此上述 Bean 实例在 SpringBoot 中涉及到 JSON 处理时,可能会有问题(这时只能说可能),例如 RestController 返回对象,会被 Jackson 转为 JSON;

复现问题

1. 这里用一个 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; }
复制代码


2. 上述代码运行起来,在浏览器访问该接口时,控制台抛出以下错误,IntOrString.getStrValue 方法,就是前面咱们看过的那段,IntOrString 中实际上保存的是 int 数据,但是 Jackson 执行了其 getStrValue 方法:


3. 至于为什么 Jackson 会执行 getStrValue 方法,篇幅原因就不在此展开了,简单提一下,在 java 客户端的 BeanPropertyWriter 类中,选择方法的逻辑如下图,红框中展示了判定逻辑,此处 getStrValue 方法命中了该逻辑,如果您尝试用在红框处打上断点观察,会发现有很多方法都符合此条件:


解决问题的思路

  • 我这里,解决问题的思路有两个:

1. 让 Jackson 在序列化的时候,能够调用正确的方法,以 IntOrString 为例,如果此时内部保存 int 型数据,就应该执行其 getIntValue 方法即可;

2. Bean 中使用了 Gson 注释,就是打算用 Gson 来处理序列化和反序列化操作的,因此序列化和反序列化的地方都改用 Gson 处理;

- 上述两个思路,我选择了第二种,毕竟第一种太难了...


解决问题

1. 问题解决起来并不难,先看 SpringBoot-2.3.1.RELEASE 官方文档:


2. 结合官方文档,我们要做两件事情:

- 首先,classpath 中有 Gson,这个已经有了,因为 K8S 官方 java 客户端会依赖 Gson;

- 其次,classpath 中不要出现 Jackson,为了达到这个目的我们需要做以下操作,排除 spring-boot-starter-web 的依赖(为什么不直接排除 jackson 的库呢?您可以执行 mvn dependency:tree 命令细看依赖树,会发现对 jackson 的依赖并非单一关系):

<dependency>	<groupId>org.springframework.boot</groupId>	<artifactId>spring-boot-starter-web</artifactId>		<exclusions>			<exclusion>				<groupId>org.springframework.boot</groupId>				<artifactId>spring-boot-starter-json</artifactId>			</exclusion>		</exclusions></dependency>
复制代码


3. 建议您执行 mvn dependency:tree 命令细看整个项目的依赖树,确保 jackson 依赖已经全部去掉;

4. 再次运行上述项目,如下图,服务端不再报错,页面上返回数据正常:


使用 Jackson 的场景

- 上述方式虽然可行,但并非所有项目都能坚持使用 Gson 而放弃 Jackson,对于使用 Jackson 的项目,请避免 Jackson 参与 K8S 官方 java 客户端 bean 的序列化和反序列化操作,以上面出现的 Controller 代码为例,不要直接将 V1PodList 实例返回,您可以选择先用 Gson 序列化成 JSON 字符串,再返回字符串给前端,也可以自己定义 VO 对象,将 V1PodList 实例转成 VO 对象再返回;

- 至此,使用 K8S 官方 java 客户端之前要注意的问题已经弄明白了,接下来的进入精彩的实战章节吧,一起体验 kubernetes 官方为 java 程序员精心准备的工具;

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 20 小时前阅读数: 20
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
Kubernetes官方java客户端之二:序列化和反序列化问题_Kubernetes_程序员欣宸_InfoQ写作平台