2

Kubernetes官方java客户端之二:序列化和反序列化问题_Kubernetes_程序员欣宸_InfoQ写...

 2 years ago
source link: https://xie.infoq.cn/article/72b313940608fc2e629565755
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

欢迎访问我的 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:程序员欣宸

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK