Diferenças entre o Java 8 e o Java 11+

A migração para os ambientes de execução do Java 11 e versões mais recentes, também conhecidos como ambientes de execução de segunda geração, permite que você use recursos de linguagem atualizados e crie apps mais portáteis com código idiomático.

Noções básicas sobre opções de migração

Para reduzir o esforço e a complexidade de migração do ambiente de execução, o ambiente padrão do App Engine permite acessar muitos serviços e APIs em pacote legados, como Memcache, nos ambientes de execução Java de segunda geração. O aplicativo Java pode chamar as APIs de serviços em pacote por meio do JAR da API do App Engine e acessar a maioria das mesmas funcionalidades no ambiente de execução do Java 8.

Você também tem a opção de usar produtos do Google Cloud que oferecem funcionalidades semelhantes aos serviços incluídos legados. Esses produtos do Google Cloud oferecem bibliotecas de cliente do Cloud para Java. Para os serviços incluídos que não estão disponíveis como produtos separados no Google Cloud, como processamento de imagens, pesquisa e mensagens, use provedores de terceiros ou outras soluções alternativas.

Para saber mais sobre como migrar para serviços desagrupados, consulte Como migrar de serviços incluídos.

Há algumas diferenças na maneira de executar a migração do ambiente de execução, dependendo de você optar por usar ou não os serviços incluídos legados:

Como migrar para o Java 11+ com serviços em pacote Como migrar para o Java 11+ sem serviços em pacote
Acesse os serviços incluídos usando o JAR das APIs do App Engine. Opcionalmente, use os produtos do Google Cloud recomendados ou serviços de terceiros.

Use appengine-web.xml e web.xml para a configuração do app.

Também pode ser necessário configurar outros arquivos YAML, dependendo dos recursos usados pelo app.

Use app.yaml para a configuração do app.

Pode ser necessário configurar outros arquivos YAML, dependendo dos recursos usados pelo app.

Os apps são implantados via Jetty. Use o formato WAR para empacotar seu aplicativo. Os aplicativos são implantados usando seu próprio servidor. Use o formato JAR para empacotar o aplicativo. Para saber mais sobre como converter o arquivo WAR existente para um JAR executável, consulte Como reempacotar um arquivo WAR.

Visão geral do processo de migração

Confira a seguir algumas alterações que talvez você precise fazer no aplicativo Java 8 do App Engine existente e no processo de implantação para usar os ambientes de execução do Java de segunda geração:

Principais diferenças entre os ambientes de execução do Java 8 e do Java 11+

Confira a seguir um resumo das diferenças entre os ambientes de execução do Java 8 e do Java 11+ no ambiente padrão do App Engine:

Ambiente de execução do Java 8 Ambientes de execução do Java 11+
Implantação do servidor Servidor implantado para você por meio do Jetty Se o app não usa os serviços incluídos no pacote, é preciso implantar um servidor por conta própria.1
Serviços agrupados do App Engine legado Fornecido Fornecido
Capacidade de usar bibliotecas de cliente do Cloud para Java Sim Sim
Extensão de linguagem e suporte à biblioteca do sistema Sim Sim
Acesso à rede externa Sim Sim
Acesso ao sistema de arquivos Acesso de leitura/gravação a /tmp Acesso de leitura/gravação a /tmp
Ambiente de execução da linguagem Modificado para o App Engine Ambiente de execução de código aberto não modificado
Mecanismo de isolamento Sandbox de contêiner com base em gVisor Sandbox de contêiner com base em gVisor
Como testar com o servidor de desenvolvimento local Compatível Compatível
Configuração de concorrência segura Pode ser especificado no arquivo appengine-web.xml. Não pode ser especificado nos arquivos de configuração. Consideramos que todos os apps são thread-safe.3
Geração de registros Usa uma java.util.logging.
ConsoleHandler, que grava em
stderr e limpa o stream
após cada registro.
Cloud Logging padrão 2

Observações:

  1. Se o aplicativo não estiver usando serviços em pacote legados, os ambientes de execução do Java de segunda geração poderão executar qualquer framework Java, desde que você empacote um servidor da Web configurado para responder a solicitações HTTP na porta especificada pela variável de ambiente PORT (recomendado) ou na porta 8080. Por exemplo, os ambientes de execução do Java de segunda geração podem executar um Uber JAR do Spring Boot como estão. Para mais exemplos, consulte a seção Flexibilidade do framework.

    Se seu aplicativo estiver usando serviços em pacote legados, o App Engine o implantará usando o Jetty da mesma forma que no ambiente de execução do Java 8.

  2. A geração de registros nos ambientes de execução do Java de segunda geração segue o padrão de geração de registros no Cloud Logging. Nos ambientes de execução do Java de segunda geração, os registros de apps não são mais agrupados com os registros de solicitação, mas são separados em registros diferentes. Para saber mais sobre como ler e gravar registros nos ambientes de execução do Java de segunda geração, consulte o guia de geração de registros.

  3. Para configurar um app não thread-safe no ambiente de execução do Java 11 de segunda geração, semelhante à definição de <threadsafe>false</threadsafe> no Java 8, defina a simultaneidade máxima como 1 em qualquer um dos arquivos app.yaml ou appengine-web.xml se estiver usando os serviços agrupados legados.

Flexibilidade do framework

Os ambientes de execução do Java de segunda geração não incluem nenhum framework de veiculação na Web, a menos que você esteja usando os serviços incluídos legados. Isso significa que você pode usar um framework diferente do baseado em servlet. Se você estiver usando os serviços incluídos legados, os ambientes de execução do Java de segunda geração fornecem o framework de veiculação na Web do Jetty.

Há amostras de hello world que usam os conhecidos frameworks da Web em Java no repositório do GitHub do Google Cloud:

Como migrar formatos de arquivo XML para YAML

A CLI gcloud não suporta os seguintes formatos de arquivo:

  • cron.xml
  • datastore-index.xml
  • dispatch.xml
  • queue.xml

Os exemplos a seguir demonstram como migrar seus arquivos xml para yaml.

Como migrar arquivos automaticamente

Para migrar seus arquivos xml automaticamente:

  1. É preciso ter a CLI gcloud versão 226.0.0 ou mais recente. Se quiser atualizar para a versão mais recente:

    gcloud components update
    
  2. Para cada arquivo que você quer migrar, especifique um dos seguintes subcomandos (cron-xml-to-yaml, datastore-indexes-xml-to-yaml, dispatch-xml-to-yaml, queue-xml-to-yaml) e o nome do arquivo:

    gcloud beta app migrate-config queue-xml-to-yaml MY-QUEUE-XML-FILE.xml
    
  3. Verifique mais uma vez manualmente o arquivo convertido antes de implantar no ambiente de produção.

    Para uma amostra de conversão de arquivo xml em yaml, consulte as guias em Como migrar seus arquivos manualmente.

Como migrar arquivos manualmente

Para migrar manualmente seus arquivos xml para yaml:

cron.yaml

Crie um arquivo cron.yaml com um objeto cron que contenha uma lista de objetos, cada um com campos que correspondem a cada um dos atributos de tag <cron> no seu arquivo cron.xml, conforme mostrado abaixo.

Arquivo cron.yaml convertido:

cron:
- url: '/recache'
  schedule: 'every 2 minutes'
  description: 'Repopulate the cache every 2 minutes'
- url: '/weeklyreport'
  schedule: 'every monday 08:30'
  target: 'version-2'
  timezone: 'America/New_York'
  description: 'Mail out a weekly report'

Arquivo cron.xml original

<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
  <cron>
    <url>/recache</url>
    <description>Repopulate the cache every 2 minutes</description>
    <schedule>every 2 minutes</schedule>
  </cron>
  <cron>
    <url>/weeklyreport</url>
    <description>Mail out a weekly report</description>
    <schedule>every monday 08:30</schedule>
    <timezone>America/New_York</timezone>
    <target>version-2</target>
  </cron>
</cronentries>

Para mais informações, consulte a documentação de referência do cron.yaml.

dispatch.yaml

Crie um arquivo dispatch.yaml com um objeto dispatch que contenha uma lista de objetos, cada um com campos que correspondem a cada um dos atributos de tag <dispatch> no seu arquivo dispatch.xml, conforme mostrado abaixo.

Arquivo dispatch.yaml convertido:

dispatch:
- url: '*/favicon.ico'
  module: default
- url: 'simple-sample.uc.r.appspot.com/'
  module: default
- url: '*/mobile/*'
  module: mobile-frontend

Arquivo dispatch.xml original

<?xml version="1.0" encoding="UTF-8"?>
<dispatch-entries>
  <dispatch>
      <url>*/favicon.ico</url>
      <module>default</module>
  </dispatch>
  <dispatch>
      <url>simple-sample.uc.r.appspot.com/</url>
      <module>default</module>
  </dispatch>
  <dispatch>
      <url>*/mobile/*</url>
      <module>mobile-frontend</module>
  </dispatch>
</dispatch-entries>

Para mais informações, consulte a documentação de referência do dispatch.yaml.

index.yaml

Crie um arquivo index.yaml com um objeto indexes contendo uma lista de objetos, cada um com campos que correspondem a cada um dos atributos de tag <datastore-index> no seu arquivo datastore-indexes.xml, conforme mostrado abaixo.

Arquivo index.yaml convertido:

indexes:
- ancestor: false
  kind: Employee
  properties:
  - direction: asc
    name: lastName
  - direction: desc
    name: hireDate
- ancestor: false
  kind: Project
  properties:
  - direction: asc
    name: dueDate
  - direction: desc
    name: cost

Arquivo datastore-index.xml original

<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes
 autoGenerate="true">
   <datastore-index kind="Employee" ancestor="false">
       <property name="lastName" direction="asc" />
       <property name="hireDate" direction="desc" />
   </datastore-index>
   <datastore-index kind="Project" ancestor="false">
       <property name="dueDate" direction="asc" />
       <property name="cost" direction="desc" />
   </datastore-index>
</datastore-indexes>

Para mais informações, consulte a documentação de referência do index.yaml.

queue.yaml

Crie um arquivo queue.yaml com um objeto queue que contenha uma lista de objetos, cada um com campos que correspondem a cada um dos atributos de tag <queue> no seu arquivo queue.xml, conforme mostrado abaixo.

Arquivo queue.yaml convertido:

queue:
- name: fooqueue
  mode: push
  rate: 1/s
  retry_parameters:
    task_retry_limit: 7
    task_age_limit: 2d
- name: barqueue
  mode: push
  rate: 1/s
  retry_parameters:
    min_backoff_seconds: 10
    max_backoff_seconds: 200
    max_doublings: 0

Arquivo queue.xml original

<queue-entries>
  <queue>
    <name>fooqueue</name>
    <rate>1/s</rate>
    <retry-parameters>
      <task-retry-limit>7</task-retry-limit>
      <task-age-limit>2d</task-age-limit>
    </retry-parameters>
  </queue>
  <queue>
    <name>barqueue</name>
    <rate>1/s</rate>
    <retry-parameters>
      <min-backoff-seconds>10</min-backoff-seconds>
      <max-backoff-seconds>200</max-backoff-seconds>
      <max-doublings>0</max-doublings>
    </retry-parameters>
  </queue>
<queue-entries>