App Engine-Anwendung von Java 8 zu Java 11 migrieren

Zusätzlich zur Unterstützung der Java 8-Laufzeit unterstützt App Engine jetzt das Hosting Ihrer Anwendungen mit der Java 11-Laufzeit. Erfahren Sie, wie Sie Ihre vorhandene App Engine-Anwendung von Java 8 zu Java 11 in der Standardumgebung migrieren.

Hauptunterschiede zwischen den Java 8- und Java 11-Laufzeiten

  • Ab der Java 11-Laufzeit enthält die App Engine-Standardumgebung keine gebündelten App Engine-Dienste mehr wie Memcache und Aufgabenwarteschlangen. Stattdessen bietet Google Cloud eigenständige Produkte, die den meisten gebündelten Diensten in der Java 11-Laufzeit entsprechen. Jedes dieser Google Cloud-Produkte bietet idiomatische Cloud Java-Clientbibliotheken. Für die gebündelten Dienste, die in Google Cloud nicht als separate Produkte verfügbar sind, wie Bildverarbeitung, Suche und Messaging, können Sie Drittanbieter oder andere Behelfslösungen verwenden, wie im Migrationsleitfaden vorgeschlagen.

    Wenn Sie die gebündelten App Engine-Dienste entfernen, unterstützt die Java 11-Laufzeit eine vollständig idiomatische Java-Entwicklung. In der Java 11-Laufzeit schreiben Sie eine Java-Standardanwendung, die vollständig portierbar ist und in jeder Java-Standardumgebung ausgeführt werden kann, einschließlich App Engine.

  • In der Java 11-Laufzeit befinden sich Konfigurationsdateien im YAML-Format und nicht im XML-Format. Geben Sie beispielsweise Einstellungen für Ihre Anwendung in der Datei app.yaml statt der Datei appengine-web.xml an. Sie müssen die Datei appengine-web.xml manuell in die Datei app.yaml konvertieren. Weitere Informationen finden Sie unter app.yaml-Datei erstellen.

    Informationen zum Konvertieren anderer Arten von App Engine-Konfigurationsdateien in YAML finden Sie unter XML-Dateien in YAML-Dateiformate migrieren.

  • Die Java 11-Laufzeit kann jedes Java-Framework ausführen, solange Sie einen Webserver verpacken. Dieser ist so konfiguriert, dass er auf HTTP-Anfragen auf dem Port antwortet, der durch die Umgebungsvariable PORT (empfohlen) oder auf Port 8080 angegeben wird. Die Java 11-Laufzeit kann zum Beispiel ein Spring Boot UberJAR in seiner Ausführung ausführen.

app.yaml-Datei erstellen

In der Java 11-Laufzeit werden die Anwendungseinstellungen in der Datei app.yaml gespeichert. Sie müssen die Datei appengine-web.xml aus Ihrer vorhandenen Anwendung entfernen und durch eine app.yaml-Datei ersetzen.

Das einzige erforderliche Element in einer app.yaml-Datei ist das Element runtime:

runtime: java11
# No need for an entrypoint with single fatjar with correct manifest class-path entry.

App Engine bietet Standardwerte für alle anderen Einstellungen, einschließlich der F1-Instanzklasse, die die Speicher- und CPU-Ressourcen bestimmt, die für Ihre Anwendung verfügbar sind, und der automatischen Skalierung, die steuert wie und wann neue Instanzen Ihrer Anwendung erstellt werden.

Der Befehl gcloud app deploy kann bei der Bereitstellung Ihrer Anwendung eine app.yaml-Datei erstellen. Die von App Engine erstellte Datei app.yaml enthält nur den runtime-Eintrag und Ihre Anwendung verwendet Standardwerte für alle Einstellungen.

Wenn Sie die Standardeinstellungen überschreiben müssen, erstellen Sie eine app.yaml-Datei und geben Sie die gewünschten Einstellungen an. Weitere Informationen finden Sie in der app.yaml-Dateireferenz.

Bei Maven-Projekten befindet sich der Standardspeicherort für die Datei app.yaml im Verzeichnis src/main/appengine. Das Maven-Plug-in für App Engine erstellt ein korrektes target/appengine-staging-Verzeichnis mit Ihren JAR-Artefakten und der zur Bereitstellung fähigen app.yaml-Datei.

Im Folgenden finden Sie ein Beispiel für eine Maven-Projektstruktur:

MyDir/
  pom.xml
  [index.yaml]
  [cron.yaml]
  [dispatch.yaml]
  src/main/
    appengine/
      app.yaml
    java/com.example.mycode/
      MyCode.java

Wenn Sie mehr als eine JAR-Datei in Ihrem Projektverzeichnis haben oder einen benutzerdefinierten Einstiegspunkt angeben möchten, müssen Sie das im Element entrypoint der Datei app.yaml angeben.

WAR-Datei in eine JAR-Datei verpacken

Für die Migration zur Java 11-Laufzeit müssen Sie Ihre App Engine Java 8-Webanwendung in eine ausführbare JAR-Datei verpacken.

Ihre Anwendung muss eine Main-Klasse haben, die einen Webserver startet. Dieser antwortet auf HTTP-Anfragen von dem Port, der mit der PORT-Umgebungsvariablen festgelegt wurde, in der Regel 8081.

Beispiel:

import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

public class Main {

  public static void main(String[] args) throws IOException {
    // Create an instance of HttpServer bound to port defined by the
    // PORT environment variable when present, otherwise on 8080.
    int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
    HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);

    // Set root URI path.
    server.createContext("/", (var t) -> {
      byte[] response = "Hello World from Google App Engine Java 11.".getBytes();
      t.sendResponseHeaders(200, response.length);
      try (OutputStream os = t.getResponseBody()) {
        os.write(response);
      }
    });

    // Start the server.
    server.start();
  }
}

Beispiel für eine WAR-Migration

In der folgenden Anleitung wird gezeigt, wie Sie eine App Engine Java 8 hello-world-Anwendung als JAR-Paket zur Ausführung in der Java 11-Laufzeit neu verpacken.

Bei der Migration wird das Artefakt appengine-simple-jetty-main verwendet. Dadurch wird eine Main-Klasse mit einem einfachen Jetty-Webserver bereitgestellt, der eine WAR-Datei lädt und Ihre Anwendung in einer ausführbaren JAR-Datei verpackt:

  1. Klonen Sie das Artefakt des eingebetteten Jetty Server auf Ihren lokalen Computer:

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples
    

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

  2. Wechseln Sie in das Verzeichnis, das den Beispielcode enthält:

    cd java-docs-samples/appengine-java11/appengine-simple-jetty-main/
    
  3. Installieren Sie die Abhängigkeit lokal:

    mvn install
    
  4. Fügen Sie der Projektdatei pom.xml folgenden Code hinzu:

    • appengine-simple-jetty-main Abhängigkeit
      <dependency>
        <groupId>com.example.appengine.demo</groupId>
        <artifactId>simple-jetty-main</artifactId>
        <version>1</version>
        <scope>provided</scope>
      </dependency>
    • maven-dependency Plug-in
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>3.1.2</version>
        <executions>
          <execution>
            <id>copy</id>
            <phase>prepare-package</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>
                ${project.build.directory}/appengine-staging
              </outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
      App Engine stellt Dateien im Verzeichnis ${build.directory}/appengine-staging bereit. Wenn Sie dem Build das Plug-in maven-dependency hinzufügen, installiert App Engine die angegebenen Abhängigkeiten in den richtigen Ordner.
  5. Erstellen Sie ein entrypoint-Element in Ihrer app.yaml-Datei, um das appengine-simple-jetty-main-Objekt aufzurufen, und übergeben Sie die WAR-Datei als Argument. Sehen Sie sich zur Veranschaulichung die Datei app.yaml des helloworld-servlet-Beispiels an:

    runtime: java11
    entrypoint: 'java -cp "*" com.example.appengine.demo.jettymain.Main helloworld.war'
  6. So führen Sie Ihre Anwendung lokal aus:

    1. Verpacken Sie Ihre Anwendung:

      mvn clean package
      
    2. Starten Sie den Server mit Ihrer WAR-Datei als Argument.

      Sie können den Server beispielsweise im helloworld-servlet-Beispiel starten, indem Sie den folgenden Befehl aus dem Ordner java-docs-samples/appengine-java11/appengine-simple-jetty-main/ ausführen:

      mvn exec:java -Dexec.args="../helloworld-java8/target/helloworld.war"
      
    3. Geben Sie im Webbrowser die folgende Adresse ein:

      http://localhost:8080

  7. So stellen Sie Ihre Anwendung bereit:

    gcloud-Tool

    gcloud app deploy

    Maven-Plug-in

    mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID

    Ersetzen Sie PROJECT_ID durch die ID Ihres Cloud-Projekts. Wenn in der Datei pom.xml bereits Ihre Projekt-ID angegeben ist, müssen Sie das Attribut -Dapp.deploy.projectId nicht in dem von Ihnen ausgeführten Befehl einfügen.

Framework-Flexibilität

Die Java 11-Laufzeit enthält kein Web-Serving-Framework, das heißt, Sie sind nicht mehr auf Servlet-basierte Frameworks beschränkt.

Im Google Cloud GitHub-Repository gibt es hello world-Beispiele, die gängige Java-Web-Frameworks verwenden:

Migration aus dem App Engine Java SDK

Die Java 11-Laufzeit unterstützt das App Engine Java SDK nicht. Im Folgenden sind einige Änderungen aufgeführt, die Sie möglicherweise an Ihrer vorhandenen App Engine Java 8-App und Ihrem Bereitstellungsprozess vornehmen müssen, um die App Engine Java 11-Laufzeit zu verwenden:

Aus App Engine-spezifischen APIs migrieren

Der Großteil der Funktionen der App Engine-spezifischen APIs wird jetzt von der Google Cloud-Clientbibliothek für Java bereitgestellt. Weitere Informationen finden Sie unten in den empfohlenen Alternativen.

Blobstore

Verwenden Sie zum Speichern und Abrufen von Daten Cloud Storage über die Cloud-Clientbibliotheken. Informationen zur Einrichtung finden Sie unter Cloud Storage verwenden.

Datastore

Verwenden Sie Cloud Firestore im Datastore-Modus als Alternative zu einer NoSQL-Schlüssel/Wert-Datenbank wie die Datastore API. Firestore ist die neueste Version von Datastore. Der Datastore-Modus wird für Datenbanken empfohlen, die hauptsächlich von App Engine-Anwendungen verwendet werden.

Bilder

Sie können Bilder aus Cloud Storage bereitstellen, entweder direkt oder mit einem Content Delivery Network (CDN) eines Drittanbieters.

Verwenden Sie zum Ändern der Größe, Konvertierung und Bearbeitung von Bildern eine Bildverarbeitungsbibliothek wie ImageJ2, imgscalr oder thumbnailator. Wenn Sie eine dieser Drittanbieterbibliotheken nutzen möchten, fügen Sie die Bibliothek als Abhängigkeit hinzu und aktualisieren Sie Ihren Code, um die APIs der Bibliothek aufzurufen.

Mit dem App Engine-Bilderdienst können Sie auch dynamische Anfragen an Ihre Anwendung vermeiden. Damit wird die Größe von Bildern mithilfe einer Bereitstellungs-URL geändert. Sie können stattdessen auch die Bilder mit der neuen Größe im Voraus generieren und dann zur Bereitstellung in Cloud Storage hochladen. Alternativ haben Sie die Möglichkeit, die Bildgröße mit einem entsprechenden externen CDN-Dienst (Content Delivery Network) zu ändern.

Logging

Wir empfehlen Ihnen, Ihre Anwendung auf die Verwendung von Cloud Logging zu aktualisieren. Diese unterstützt Funktionen wie das Aufrufen von Logs in der Loganzeige, das Herunterladen von Logs, das Filtern von Nachrichten nach Schweregrad und die Korrelation von Anwendungsnachrichten mit bestimmten Anfragen. Alternativ können Sie diese Funktionen aktivieren, indem Sie Lognachrichten schreiben, die bestimmte in einem JSON-Objekt strukturierte Daten enthalten.

Weitere Informationen finden Sie unter Logs schreiben und ansehen.

Mail

Verwenden Sie zum Senden von E-Mails einen Drittanbieter wie SendGrid, Mailgun oder Mailjet. Alle diese Dienste bieten APIs zum Senden von E-Mails aus Anwendungen.

Memcache

Verwenden Sie zum Speichern von Anwendungsdaten Memorystore for Redis.

Module

Zum Abrufen von Informationen und zum Ändern der ausgeführten Dienste Ihrer Anwendung verwenden Sie eine Kombination aus Umgebungsvariablen und der App Engine Admin API:

Dienstinformation Zugriff
Aktuelle Anwendungs-ID Umgebungsvariable GAE_APPLICATION
Aktuelle Projekt-ID Umgebungsvariable GOOGLE_CLOUD_PROJECT
Aktueller Dienstname Umgebungsvariable GAE_SERVICE
Aktuelle Dienstversion Umgebungsvariable GAE_VERSION
Aktuelle Instanz-ID Umgebungsvariable GAE_INSTANCE
Standardhostname Admin API-Methode apps.get
Liste der Dienste Admin API-Methode apps.services.list
Liste der Versionen für einen Dienst Admin API-Methode apps.services.versions.list
Standardversion für einen Dienst, inklusive Traffic-Aufteilung Admin API-Methode apps.services.get
Liste der für eine Version ausgeführten Instanzen Admin API-Methode apps.services.versions.instances.list
Weitere Informationen zu den Daten, die zu den ausgeführten Diensten Ihrer Anwendung verfügbar sind, finden Sie unter Java 11-Laufzeitumgebung.

Namespaces

Mit der Namespaces API konnten mehrinstanzenfähige Anwendungen Daten nach Mandanten partitionieren. Dazu wurde für jeden Mandanten einfach ein eindeutiger Namespace-String festgelegt.

Datastore unterstützt die Mehrinstanzenfähigkeit direkt, andere Google Cloud-Dienste dagegen nicht. Wenn Ihre mehrinstanzenfähige Anwendung andere Google Cloud-Dienste verwendet, müssen Sie die Mehrinstanzenfähigkeit manuell festlegen. Sie können mit der Cloud Resource Manager API programmatisch neue Projekte erstellen und projektübergreifend auf Ressourcen zugreifen, um Dienstinstanzen vollständig zu isolieren.

OAuth

Verwenden Sie zum Prüfen von OAuth 2.0-Tokens nicht den App Engine-OAuth-Dienst, sondern die Methode oauth2.tokeninfo der OAuth 2.0-API.

Hosten Sie eine Volltextsuchdatenbank wie Elasticsearch in Compute Engine und greifen Sie von Ihrem Dienst aus darauf zu.

Aufgabenwarteschlange

Stellen Sie Aufgaben für die asynchrone Codeausführung mithilfe der Cloud Tasks REST API, RPC API oder der Google Cloud-Clientbibliothek in die Warteschlange und verwenden Sie einen Java 11 App Engine-Standarddienst als Push-Ziel. Weitere Informationen finden Sie unter Von Aufgabenwarteschlangen zu Cloud Tasks migrieren.

In vielen Fällen, in denen Sie Pull-Warteschlangen verwenden können, z. B. für Aufgaben oder Nachrichten, die von unterschiedlichen Workern abgerufen und verarbeitet werden, bietet Pub/Sub eine empfehlenswerte Alternative, die ähnliche Funktionen und Zustellgarantien bietet. Sehen Sie sich zur Veranschaulichung das Beispielprogramm an, das mit der Cloud Tasks API interagiert.

Nutzerauthentifizierung

Verwenden Sie als Alternative zur Users API einen beliebigen HTTP-basierten Authentifizierungsmechanismus, beispielsweise:

XML-Dateien in YAML-Dateien migrieren

Das Cloud SDK unterstützt die folgenden Dateiformate nicht:

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

Die folgenden Beispiele zeigen, wie Sie Ihre xml-Dateien in yaml-Dateien migrieren können.

Dateien automatisch migrieren

So migrieren Sie Ihre xml-Dateien automatisch:

  1. Sie benötigen die Cloud SDK-Version 226.0.0 oder höher. So führen Sie ein Update auf die neueste Version aus:

    gcloud components update
    
  2. Geben Sie für jede Datei, die Sie migrieren möchten, einen der folgenden Unterbefehle (cron-xml-to-yaml, datastore-indexes-xml-to-yaml, dispatch-xml-to-yaml, queue-xml-to-yaml ) und den Dateinamen an:

    gcloud beta app migrate-config queue-xml-to-yaml MY-QUEUE-XML-FILE.xml
    
  3. Prüfen Sie manuell die konvertierte Datei, bevor Sie sie in der Produktionsumgebung bereitstellen.

    Eine Beispielkonvertierung von xml zu yaml finden Sie unter den Tabs Dateien manuell migrieren.

Dateien manuell migrieren

So migrieren Sie Ihre xml-Dateien manuell in yaml-Dateien:

cron.yaml

Erstellen Sie eine Datei cron.yaml mit einem cron-Objekt. Dieses muss wiederum Objekte jeweils mit den Feldern enthalten, die den <cron>-Tag-Attributen in Ihrer cron.xml-Datei entsprechen, wie unten gezeigt.

Konvertierte cron.yaml-Datei:

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'

Original cron.xml-Datei:

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

Weitere Informationen finden Sie in der Referenzdokumentation zu cron.yaml.

dispatch.yaml

Erstellen Sie eine dispatch.yaml-Datei mit einem dispatch-Objekt. Dieses muss wiederum Objekte jeweils mit den Feldern enthalten, die den <dispatch>-Tag-Attributen in Ihrer dispatch.xml-Datei entsprechen, wie unten gezeigt.

Konvertierte dispatch.yaml-Datei:

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

Original dispatch.xml-Datei:

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

Weitere Informationen finden Sie in der Referenzdokumentation zu dispatch.yaml.

index.yaml

Erstellen Sie eine index.yaml-Datei mit einem indexes-Objekt. Dieses muss wiederum Objekte jeweils mit den Feldern enthalten, die den <datastore-index>-Tag-Attributen in Ihrer datastore-indexes.xml-Datei entsprechen, wie unten gezeigt.

Konvertierte index.yaml-Datei:

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

Original datastore-index.xml-Datei:

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

Weitere Informationen finden Sie in der Referenzdokumentation zu index.yaml.

queue.yaml

Erstellen Sie eine queue.yaml-Datei mit einem queue-Objekt. Dieses muss wiederum Objekte jeweils mit den Feldern enthalten, die den <queue>-Tag-Attributen in Ihrer queue.xml-Datei entsprechen, wie unten gezeigt.

Konvertierte queue.yaml-Datei:

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

Original queue.xml-Datei:

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