Bem-vindo ao meu GitHub
https://github.com/zq2599/blog_demos
Cenário de problema
Este artigo é o segundo capítulo do "Cliente Java oficial do Kubernetes". Antes de entrar no capítulo de codificação real, há um problema que exige que todos tenham compreensão suficiente para evitar o gasto de energia para lidar com esse tipo de problema no combate real subsequente. Vamos ver o que é. problema:
-
SpringBoot é uma estrutura de aplicativo comumente usada. Os aplicativos da série "Kubernetes Official Java Client" são todos baseados na versão SpringBoot-2.3.1;
-
A figura a seguir é o documento oficial do SpringBoot-2.3.1.RELEASE. A caixa vermelha indica que a biblioteca de processamento JSON padrão é Jackson:
-
Vendo isso, você tem um pressentimento sinistro: o cliente Java oficial do K8S é o Google. Quando se trata de processamento JSON, seu próprio Gson será preferido?
-
V1HTTPGetAction.java é uma estrutura de dados comumente usada em clientes java. É usada para encapsular os parâmetros relacionados à solicitação http. Vamos dar uma olhada no código-fonte. Conforme mostrado na figura abaixo, ele realmente usa as anotações de Gson:
-
A classe IntOrString mencionada na figura acima deve ser focada e tem uma ampla gama de usos. Abra seu código-fonte conforme mostrado na figura abaixo. Anote o código na caixa vermelha 2. O problema mencionado mais tarde vem deste:
- Resumo: A classe de processamento JSON padrão do SpringBoot é Jackson. O Bean no cliente K8S java oficial usa anotações Gson quando se trata de serialização e desserialização relacionadas a JSON. Portanto, a instância Bean acima envolve processamento JSON no SpringBoot. Neste momento, pode haver problemas (só podemos dizer isso neste momento), por exemplo, o objeto retornado por RestController será convertido para JSON por Jackson;
Problema recorrente
- Aqui está um projeto SpringBoot para demonstrar esse problema (o projeto é denominado OutsideclusterApplication, que será explicado em detalhes no próximo artigo). O código a seguir é uma resposta de interface http. Pode-se ver que quando a instância V1PodList é retornada como uma interface, ela será convertida em JSON por SpringBoot usando Jackson a parte dianteira:
@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;
}
-
O código acima é executado. Quando o navegador acessa a interface, o console emite o seguinte erro. O método IntOrString.getStrValue é o parágrafo que vimos antes. IntOrString na verdade armazena dados internos, mas Jackson executa seu getStrValue método:
-
Quanto ao motivo de Jackson executar o método getStrValue, o comprimento do motivo não será expandido aqui. Basta mencionar que na classe BeanPropertyWriter do cliente Java, a lógica do método de seleção é mostrada na figura a seguir. A caixa vermelha mostra a lógica de determinação. Aqui, o método getStrValue acerta isso Lógica, se você tentar observar com um ponto de interrupção na caixa vermelha, verá que existem muitos métodos que atendem a esta condição:
Ideias para resolver o problema
Aqui, tenho duas ideias para resolver o problema:
- Permita que Jackson chame o método correto durante a serialização. Tome IntOrString como exemplo. Se os dados int forem armazenados internamente neste momento, seu método getIntValue deve ser executado;
- A anotação Gson é usada em Bean, que se destina a usar Gson para lidar com operações de serialização e desserialização, portanto, a serialização e a desserialização são alteradas para processamento Gson;
- Para as duas ideias acima, escolhi a segunda, afinal a primeira é muito difícil ...
Resolva o problema
-
O problema não é difícil de resolver, primeiro olhe o documento oficial SpringBoot-2.3.1.RELEASE:
-
Combinado com documentos oficiais, temos que fazer duas coisas:
- Em primeiro lugar, há Gson no caminho de classe, ele já está lá, porque o cliente Java oficial K8S contará com Gson;
- Em segundo lugar, não inclua Jackson no caminho de classe. Para conseguir isso, precisamos fazer o seguinte para excluir a dependência de spring-boot-starter-web (por que não excluir diretamente a biblioteca de Jackson? Você pode executar o comando mvn dependency: tree para examinar mais de perto a árvore de dependência , Você verá que a dependência de jackson não é um único relacionamento):
<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>
- É recomendado que você execute o comando mvn dependency: tree para examinar mais de perto a árvore de dependências de todo o projeto para garantir que todas as dependências de jackson foram removidas;
- Execute o projeto acima novamente, conforme mostrado na figura abaixo, o servidor não reporta mais um erro e os dados retornados na página são normais:
Cenas usando Jackson
-
Embora o método acima seja viável, nem todos os projetos podem aderir ao Gson e desistir de Jackson. Para projetos que usam Jackson, evite que Jackson participe da serialização e desserialização de beans de cliente java oficial K8S. Pegue o código do controlador que aparece acima como Por exemplo, não retorne a instância V1PodList diretamente. Você pode escolher serializá-la em uma string JSON com Gson primeiro e, em seguida, retornar a string para o front end ou pode definir seu próprio objeto VO, converter a instância V1PodList em um objeto VO e depois retornar;
-
Neste ponto, os problemas aos quais devemos prestar atenção antes de usar o cliente Java oficial do K8S foram resolvidos.A seguir, vamos entrar no maravilhoso capítulo prático e experimentar as ferramentas cuidadosamente preparadas pelo oficial do Kubernetes para programadores Java;