Differenze tra Java 8 e Java 11 e versioni successive

La migrazione ai runtime Java 11 e versioni successive, noti anche come runtime Java di seconda generazione, ti consente di utilizzare funzionalità del linguaggio aggiornate e di creare app più portabili, con codice idiomatico.

Informazioni sulle opzioni di migrazione

Per ridurre lo sforzo e la complessità della migrazione al runtime, l'ambiente standard di App Engine consente di accedere a molti servizi e API legacy in bundle, come Memcache, nei runtime Java di seconda generazione. L'app Java può chiamare le API dei servizi in bundle tramite il JAR dell'API App Engine e accedere alla maggior parte delle stesse funzionalità del runtime Java 8.

Hai anche la possibilità di utilizzare prodotti Google Cloud che offrono funzionalità simili a quelle dei servizi in bundle legacy. Questi prodotti Google Cloud forniscono librerie client Cloud per Java idiomatiche. Per i servizi in bundle che non sono disponibili come prodotti separati in Google Cloud, ad esempio l'elaborazione di immagini, la ricerca e la messaggistica, puoi utilizzare fornitori di terze parti o altre soluzioni alternative.

Per saperne di più sulla migrazione a servizi non in bundle, consulta Migrazione dai servizi in bundle.

Esistono alcune differenze nel modo in cui esegui la migrazione di runtime, a seconda che tu scelga o meno di utilizzare i servizi in bundle legacy:

Migrazione ai runtime Java 11 e versioni successive con servizi in bundle Migrazione ai runtime Java 11 e versioni successive senza servizi in bundle
Accedi ai servizi in bundle utilizzando il JAR delle API di App Engine. (Facoltativo) Utilizza i prodotti Google Cloud consigliati o i servizi di terze parti.

Utilizza appengine-web.xml e web.xml per la configurazione dell'app.

Potresti anche dover configurare file YAML aggiuntivi a seconda delle funzionalità utilizzate dalla tua app.

Utilizza app.yaml per la configurazione dell'app.

Potresti anche dover configurare file YAML aggiuntivi a seconda delle funzionalità utilizzate dalla tua app.

Il deployment delle app viene eseguito tramite Jetty. Usa il formato WAR per pacchettizzare la tua app. Il deployment delle app viene eseguito utilizzando il tuo server. Utilizza il formato JAR per pacchettizzare la tua app. Per scoprire di più sulla conversione del file WAR esistente in un JAR eseguibile, consulta Ricompacchettare un file WAR.

Panoramica del processo di migrazione

Di seguito sono elencate alcune modifiche che potresti dover apportare all'app Java 8 di App Engine esistente e al processo di deployment per utilizzare i runtime Java di seconda generazione:

Differenze principali tra i runtime Java 8 e Java 11 e versioni successive

Di seguito è riportato un riepilogo delle differenze tra i runtime Java 8 e Java 11 e versioni successive nell'ambiente standard di App Engine:

Runtime Java 8 Runtime Java 11 e versioni successive
Deployment server Server di cui è stato eseguito il deployment tramite Jetty Se la tua app non utilizza i servizi in bundle legacy, devi eseguire il deployment di un server autonomamente.1
Servizi in bundle legacy di App Engine Fornito da Google Fornito da Google
Possibilità di utilizzare le librerie client di Cloud per Java
Supporto delle estensioni di lingua e della libreria di sistema
Accesso alla rete esterna
Accesso al file system Accesso in lettura/scrittura a /tmp Accesso in lettura/scrittura a /tmp
Runtime del linguaggio Modificato per App Engine Runtime open source non modificato
Meccanismo di isolamento Sandbox del container basata su gVisor Sandbox del container basata su gVisor
Test con il server di sviluppo locale Supportato Supportato
Configurazione di sicurezza Thread Può essere specificato nel file appengine-web.xml. Non può essere specificato nei file di configurazione. Si presume che tutte le app siano compatibili con i thread.3
Logging Utilizza un valore java.util.logging.
ConsoleHandler, che scrive in
stderr ed elimina il flusso
dopo ogni record.
Cloud Logging standard2

Note:

  1. Se la tua app non utilizza i servizi in bundle legacy, i runtime Java di seconda generazione possono eseguire qualsiasi framework Java, purché crei un pacchetto di un server web configurato per rispondere alle richieste HTTP sulla porta specificata dalla variabile di ambiente PORT (consigliata) o sulla porta 8080. Ad esempio, i runtime Java di seconda generazione possono eseguire un Uber JAR Spring Boot così com'è. Per altri esempi, consulta la sezione Flessibilità del framework.

    Se la tua app utilizza i servizi in bundle legacy, App Engine ne esegue il deployment utilizzando Jetty come nel runtime Java 8.

  2. Il logging nei runtime Java di seconda generazione segue lo standard di logging in Cloud Logging. Nei runtime Java di seconda generazione, i log delle app non sono più in bundle con i log delle richieste, ma sono separati in record diversi. Per scoprire di più sulla lettura e sulla scrittura di log nei runtime Java di seconda generazione, consulta la guida al logging.

  3. Per configurare un'app non threadsafe nel runtime Java di seconda generazione, in modo simile all'impostazione di <threadsafe>false</threadsafe> in Java 8, imposta la contemporaneità massima su 1 nel file app.yaml o nel file appengine-web.xml se utilizzi i servizi legacy in bundle.

Flessibilità del framework

I runtime Java di seconda generazione non includono framework di pubblicazione web, a meno che tu non utilizzi i servizi in bundle legacy. Ciò significa che puoi utilizzare un framework diverso da quello basato su servlet. Se utilizzi i servizi in bundle legacy, i runtime Java di seconda generazione forniscono il framework di pubblicazione web Jetty.

Esistono hello world esempi che utilizzano framework web Java popolari nel repository GitHub di Google Cloud:

Migrazione di XML in formati di file YAML

Gcloud CLI non supporta i seguenti formati file:

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

I seguenti esempi mostrano come eseguire la migrazione dei file xml in file yaml.

Migrazione automatica dei file

Per eseguire la migrazione automatica dei file xml:

  1. Devi avere gcloud CLI versione 226.0.0 o successive. Per eseguire l'aggiornamento alla versione più recente:

    gcloud components update
    
  2. Per ogni file di cui vuoi eseguire la migrazione, specifica uno dei seguenti sottocomandi (cron-xml-to-yaml, datastore-indexes-xml-to-yaml, dispatch-xml-to-yaml, queue-xml-to-yaml) e il nome del file:

    gcloud beta app migrate-config queue-xml-to-yaml MY-QUEUE-XML-FILE.xml
    
  3. Controlla manualmente il file convertito prima del deployment in produzione.

    Per un esempio di conversione di file da xml a yaml riuscita, consulta la scheda Migrazione manuale dei file.

Migrazione manuale dei file

Per eseguire la migrazione manuale dei file xml in yaml file:

cron.yaml

Crea un file cron.yaml con un oggetto cron contenente un elenco di oggetti, ciascuno con campi corrispondenti a ciascuno degli attributi del tag <cron> nel file cron.xml, come mostrato di seguito.

File cron.yaml convertito:

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'

File cron.xml originale:

<?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>

Per ulteriori informazioni, consulta la documentazione di riferimento cron.yaml.

dispatch.yaml

Crea un file dispatch.yaml con un oggetto dispatch contenente un elenco di oggetti, ciascuno con campi corrispondenti a ciascuno degli attributi del tag <dispatch> nel file dispatch.xml, come mostrato di seguito.

File dispatch.yaml convertito:

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

File originale dispatch.xml

<?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>

Per ulteriori informazioni, consulta la documentazione di riferimento dispatch.yaml

index.yaml

Crea un file index.yaml con un oggetto indexes contenente un elenco di oggetti, ciascuno con campi corrispondenti a ciascuno degli attributi del tag <datastore-index> nel file datastore-indexes.xml, come mostrato di seguito.

File index.yaml convertito:

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

File datastore-index.xml originale:

<?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>

Per ulteriori informazioni, consulta la documentazione di riferimento index.yaml.

queue.yaml

Crea un file queue.yaml con un oggetto queue contenente un elenco di oggetti, ciascuno con campi corrispondenti a ciascuno degli attributi del tag <queue> nel file queue.xml, come mostrato di seguito.

File queue.yaml convertito:

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

File queue.xml originale:

<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>