Vuelve a empaquetar un archivo WAR en un archivo JAR

Si migras a la versión más reciente compatible de Java y tu aplicación no usa los servicios empaquetados heredados, debes volver a empaquetar tu aplicación web de App Engine en un archivo JAR ejecutable.

Tu aplicación debe tener una clase Main que inicie un servidor web que responda a las solicitudes HTTP en el puerto 8080, que podría especificarse con la variable de entorno PORT.

Por ejemplo:

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.Configuration.ClassList;
import org.eclipse.jetty.webapp.WebAppContext;

/** Simple Jetty Main that can execute a WAR file when passed as an argument. */
public class Main {

  public static void main(String[] args) throws Exception {
    if (args.length != 1) {
      System.err.println("Usage: need a relative path to the war file to execute");
      System.exit(1);
    }
    System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StrErrLog");
    System.setProperty("org.eclipse.jetty.LEVEL", "INFO");

    // Create a basic Jetty server object that will listen on port defined by
    // the PORT environment variable when present, otherwise on 8080.
    int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
    Server server = new Server(port);

    // The WebAppContext is the interface to provide configuration for a web
    // application. In this example, the context path is being set to "/" so
    // it is suitable for serving root context requests.
    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath("/");
    webapp.setWar(args[0]);
    ClassList classlist = ClassList.setServerDefault(server);

    // Enable Annotation Scanning.
    classlist.addBefore(
        "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
        "org.eclipse.jetty.annotations.AnnotationConfiguration");

    // Set the the WebAppContext as the ContextHandler for the server.
    server.setHandler(webapp);

    // Start the server! By using the server.join() the server thread will
    // join with the current thread. See
    // "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()"
    // for more details.
    server.start();
    server.join();
  }
}

Ejemplo de migración de WAR (Java 21)

En las siguientes instrucciones, se muestra cómo volver a empaquetar una aplicación hello-world WAR de App Engine como un JAR para que se ejecute en el entorno de ejecución de Java 21.

La migración usa el artefacto appengine-simple-jetty-main. Esto proporciona una clase Main con un servidor web Jetty simple que carga un archivo WAR y empaqueta tu app en un archivo JAR ejecutable:

  1. Clona el artefacto del servidor Jetty incorporado en tu máquina local:

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

    De manera opcional, puedes descargar la muestra como un archivo ZIP y extraerla.

  2. Dirígete al directorio que contiene el código de muestra:

    cd java-docs-samples/flexible/repacking-legacy-applications/appengine-simple-jetty-main/
    
  3. Compila el JAR del ejecutor de Jetty:

    mvn install
    

    Esto genera jetty-jar-with-dependencies.jar en tu directorio target/.

  4. Configura el archivo de compilación pom.xml para el servidor de Jetty:

    • Propiedades del compilador (Java 21):
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <jetty.version>9.4.57.v20241219</jetty.version>
      </properties>
    • Dependencias de Jetty integradas:
      <dependencies>
        <!-- Embedded Jetty dependencies -->
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-server</artifactId>
          <version>${jetty.version}</version>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-webapp</artifactId>
          <version>${jetty.version}</version>
          <type>jar</type>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-util</artifactId>
          <version>${jetty.version}</version>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-annotations</artifactId>
          <version>${jetty.version}</version>
        </dependency>
        <!-- extra explicit dependency needed because there is a JSP in the sample-->
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>apache-jsp</artifactId>
          <version>${jetty.version}</version>
        </dependency>
      </dependencies>
    • Configuración de maven-assembly-plugin:
      
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.0.0</version>
        <configuration>
          <finalName>jetty</finalName>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>com.example.appengine.jetty.Main</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      
  5. Coloca el archivo jetty-jar-with-dependencies.jar generado y el archivo WAR de tu aplicación. Por ejemplo, helloworld.war en el mismo directorio.

  6. Crea un archivo app.yaml en el directorio de tu aplicación para especificar el tiempo de ejecución de Java 21 y un elemento entrypoint para llamar al archivo jetty-jar-with-dependencies.jar y pasar tu archivo WAR como argumento:

    runtime: java21
    entrypoint: 'java -jar jetty-jar-with-dependencies.jar helloworld.war'
    
  7. Para ejecutar tu aplicación de forma local, sigue estos pasos:

    1. Inicia el servidor con tu archivo WAR como argumento:

      java -jar jetty-jar-with-dependencies.jar helloworld.war
      
    2. En el navegador web, ingresa la siguiente dirección:

      http://localhost:8080

  8. Para implementar tu aplicación, ejecuta el siguiente comando:

    Herramientas de gcloud

    gcloud app deploy

    Complemento de Maven

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

    Reemplaza PROJECT_ID por el ID de tu proyecto de Google Cloud . Si tu archivo pom.xml ya especifica tu ID del proyecto, no necesitas incluir la propiedad -Dapp.deploy.projectId en el comando que ejecutas.