App Engine Java 11 在实际服务器上找不到或加载不了主类。

huangapple go评论81阅读模式
英文:

App Engine Java 11 could not find or load main class on live server

问题

在本地运行时,我的网页应用程序运行正常,但是当我部署到我的实时App Engine项目时,出现问题。

我正在尝试使用Java 11版本的App Engine创建一个基本的基于Servlet的Web应用程序。我正在按照这个指南从Java 8升级到Java 11的一些项目。我还使用了这个指南这个示例。我的目标是使用Jetty运行一个非常简单的Web应用程序,在App Engine中提供一个单独的静态HTML文件和一个Servlet文件。

当我在本地运行时,我的Web应用程序运行正常:

mvn clean install
mvn exec:java -Dexec.args="target/app-engine-hello-world-1.war"

当我运行这些命令时,我的index.html和我的Servlet URL 都可以正常工作。

但是当我部署到我的实时站点时:

mvn package appengine:deploy

...命令成功执行,但是当我导航到我的实时URL时,对于HTML文件和Servlet URL,我都会收到以下错误消息:"Error: Server Error. The server encountered an error and could not complete your request. Please try again in 30 seconds." 如果我查看Cloud控制台中的日志,我会看到以下错误:

Error: Could not find or load main class io.happycoding.Main
Caused by: java.lang.ClassNotFoundException: io.happycoding.Main

我的设置似乎存在问题,但我没有看到明显的错误。

这是我的项目中的文件:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>io.happycoding</groupId>
  <artifactId>app-engine-hello-world</artifactId>
  <version>1</version>
  <packaging>war</packaging>

  <properties>
    <!-- App Engine currently supports Java 11 -->
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <failOnMissingWebXml>false</failOnMissingWebXml>
  </properties>

  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-server</artifactId>
      <version>9.4.31.v20200723</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-webapp</artifactId>
      <version>9.4.31.v20200723</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-util</artifactId>
      <version>9.4.31.v20200723</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-annotations</artifactId>
      <version>9.4.31.v20200723</version>
      <type>jar</type>
    </dependency>

  </dependencies>

  <build>
    <plugins>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.0.0</version>
        <executions>
          <execution>
            <goals>
              <goal>java</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <mainClass>io.happycoding.Main</mainClass>
        </configuration>
      </plugin>

      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>appengine-maven-plugin</artifactId>
        <version>2.2.0</version>
        <configuration>
          <projectId>happy-coding-gcloud</projectId>
          <version>1</version>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

src/main/appengine/app.yaml

runtime: java11
entrypoint: 'java -cp "*" io.happycoding.Main app-engine-hello-world-1.war'

src/main/java/io/happycoding/Main.java

package io.happycoding;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.webapp.Configuration.ClassList;
import org.eclipse.jetty.webapp.WebAppContext;
import io.happycoding.servlets.HelloWorldServlet;

/** 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");

    Server server = new Server(8080);

    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");

    server.setHandler(webapp);
    server.join();
  }
}

src/main/webapp/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Google Cloud Hello World</title>
  </head>
  <body>
    <h1>Google Cloud Hello World</h1>
    <p>This is a sample HTML file.

<details>
<summary>英文:</summary>

**tl;dr:** Why does this work locally but not when I deploy to my live App Engine project?

I&#39;m trying to create a barebones servlet-based web app using the Java 11 version of App Engine. I&#39;m updating a few projects from Java 8  to Java 11 following [this guide](https://cloud.google.com/appengine/docs/standard/java11/java-differences). I&#39;m also using [this guide](https://cloud.google.com/appengine/docs/standard/java11/runtime#application_startup) and [this example](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/appengine-java11/appengine-simple-jetty-main). My goal is to use Jetty to run a very simple web app that serves a single static HTML file and a single servlet file in App Engine.

My web app works fine when I run locally:

mvn clean install
mvn exec:java -Dexec.args="target/app-engine-hello-world-1.war"


When I run these commands, both my `index.html` and my servlet URL work fine.
But when I deploy to my live site:

mvn package appengine:deploy


...the command succeeds, but when I navigate to my live URL, I get this error for both the HTML file and the servlet URL: `&quot;Error: Server Error. The server encountered an error and could not complete your request. Please try again in 30 seconds.&quot;` If I look in the logs in the Cloud console, I see this error:

Error: Could not find or load main class io.happycoding.Main
Caused by: java.lang.ClassNotFoundException: io.happycoding.Main


Something is off with my setup, but I don&#39;t see anything obviously wrong.
Here are the files in my project:
**pom.xml**
```xml
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;groupId&gt;io.happycoding&lt;/groupId&gt;
&lt;artifactId&gt;app-engine-hello-world&lt;/artifactId&gt;
&lt;version&gt;1&lt;/version&gt;
&lt;packaging&gt;war&lt;/packaging&gt;
&lt;properties&gt;
&lt;!-- App Engine currently supports Java 11 --&gt;
&lt;maven.compiler.source&gt;11&lt;/maven.compiler.source&gt;
&lt;maven.compiler.target&gt;11&lt;/maven.compiler.target&gt;
&lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
&lt;failOnMissingWebXml&gt;false&lt;/failOnMissingWebXml&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;javax.servlet&lt;/groupId&gt;
&lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
&lt;version&gt;4.0.1&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
&lt;artifactId&gt;jetty-server&lt;/artifactId&gt;
&lt;version&gt;9.4.31.v20200723&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
&lt;artifactId&gt;jetty-webapp&lt;/artifactId&gt;
&lt;version&gt;9.4.31.v20200723&lt;/version&gt;
&lt;type&gt;jar&lt;/type&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
&lt;artifactId&gt;jetty-util&lt;/artifactId&gt;
&lt;version&gt;9.4.31.v20200723&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
&lt;artifactId&gt;jetty-annotations&lt;/artifactId&gt;
&lt;version&gt;9.4.31.v20200723&lt;/version&gt;
&lt;type&gt;jar&lt;/type&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
&lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;
&lt;version&gt;3.0.0&lt;/version&gt;
&lt;executions&gt;
&lt;execution&gt;
&lt;goals&gt;
&lt;goal&gt;java&lt;/goal&gt;
&lt;/goals&gt;
&lt;/execution&gt;
&lt;/executions&gt;
&lt;configuration&gt;
&lt;mainClass&gt;io.happycoding.Main&lt;/mainClass&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;plugin&gt;
&lt;groupId&gt;com.google.cloud.tools&lt;/groupId&gt;
&lt;artifactId&gt;appengine-maven-plugin&lt;/artifactId&gt;
&lt;version&gt;2.2.0&lt;/version&gt;
&lt;configuration&gt;
&lt;projectId&gt;happy-coding-gcloud&lt;/projectId&gt;
&lt;version&gt;1&lt;/version&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;/project&gt;

src/main/appengine/app.yaml

runtime: java11
entrypoint: &#39;java -cp &quot;*&quot; io.happycoding.Main app-engine-hello-world-1.war&#39;

src/main/java/io/happycoding/Main.java

package io.happycoding;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.webapp.Configuration.ClassList;
import org.eclipse.jetty.webapp.WebAppContext;
import io.happycoding.servlets.HelloWorldServlet;

/** 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(&quot;Usage: need a relative path to the war file to execute&quot;);
      System.exit(1);
    }
    System.setProperty(&quot;org.eclipse.jetty.util.log.class&quot;, &quot;org.eclipse.jetty.util.log.StrErrLog&quot;);
    System.setProperty(&quot;org.eclipse.jetty.LEVEL&quot;, &quot;INFO&quot;);

    Server server = new Server(8080);

    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath(&quot;/&quot;);
    webapp.setWar(args[0]);
    ClassList classlist = ClassList.setServerDefault(server);

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

    server.setHandler(webapp);
    server.join();
  }
}

src/main/webapp/index.html

&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;Google Cloud Hello World&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Google Cloud Hello World&lt;/h1&gt;
    &lt;p&gt;This is a sample HTML file. Click &lt;a href=&quot;/hello&quot;&gt;here&lt;/a&gt; to see content served from a servlet.&lt;/p&gt;
    &lt;p&gt;Learn more at &lt;a href=&quot;https://happycoding.io&quot;&gt;HappyCoding.io&lt;/a&gt;.&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;

src/main/java/io/happycoding/servlets/HelloWorldServlet.java

package io.happycoding.servlets;

import java.io.IOException;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(&quot;/hello&quot;)
public class HelloWorldServlet extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType(&quot;text/html;&quot;);
    response.getOutputStream().println(&quot;&lt;h1&gt;Hello world!&lt;/h1&gt;&quot;);
  }
}

I'm guessing something is off with how I'm setting the classpath of the live site, but I don't see anything obviously wrong.

With the packaging property in pom.xml set to war, I get a .war file with these contents:

index.html
META-INF/MANIFEST.MF
META-INF/maven/io.happycoding/app-engine-hello-world/pom.properties
META-INF/maven/io.happycoding/app-engine-hello-world/pom.xml
WEB-INF/classes/io/happycoding/Main.class
WEB-INF/classes/io/happycoding/servlets/HelloWorldServlet.class
WEB-INF/classes/lib/asm-7.3.1.jar
WEB-INF/classes/lib/asm-analysis-7.3.1.jar
WEB-INF/classes/lib/asm-commons-7.3.1.jar
WEB-INF/classes/lib/asm-tree-7.3.1.jar
WEB-INF/classes/lib/javax.annotation-api-1.3.jar
WEB-INF/classes/lib/javax.servlet-api-4.0.1.jar
WEB-INF/classes/lib/jetty-annotations-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-http-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-io-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-jndi-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-plus-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-security-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-server-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-servlet-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-util-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-webapp-9.4.31.v20200723.jar
WEB-INF/classes/lib/jetty-xml-9.4.31.v20200723.jar

If I change the packaging property in pom.xml to jar, then I get a .jar file with these contents:

io/happycoding/Main.class
io/happycoding/servlets/HelloWorldServlet.class
META-INF/MANIFEST.MF
META-INF/maven/io.happycoding/app-engine-hello-world/pom.properties
META-INF/maven/io.happycoding/app-engine-hello-world/pom.xml

And I get this error in the logs for the live site instead:

Error: Unable to initialize main class io.happycoding.Main 
Caused by: java.lang.NoClassDefFoundError: org/eclipse/jetty/server/Handler 

That feels like progress, but then I also get 404 errors in my live server, so I feel pretty stuck.

What do I need to change about my above setup to make it work both locally and on my live server?

Edit: I can see the following files in the App Engine debugger:

App Engine Java 11 在实际服务器上找不到或加载不了主类。

I tried adding this to my pom.xml file:

&lt;plugin&gt;
  &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
  &lt;artifactId&gt;maven-dependency-plugin&lt;/artifactId&gt;
  &lt;version&gt;3.1.2&lt;/version&gt;
  &lt;executions&gt;
    &lt;execution&gt;
      &lt;id&gt;copy&lt;/id&gt;
      &lt;phase&gt;prepare-package&lt;/phase&gt;
      &lt;goals&gt;
        &lt;goal&gt;copy-dependencies&lt;/goal&gt;
      &lt;/goals&gt;
      &lt;configuration&gt;
        &lt;outputDirectory&gt;
          ${project.build.directory}/appengine-staging
        &lt;/outputDirectory&gt;
      &lt;/configuration&gt;
    &lt;/execution&gt;
  &lt;/executions&gt;
&lt;/plugin&gt;

Then I see these file in the App Engine debugger:

App Engine Java 11 在实际服务器上找不到或加载不了主类。

But I still get the same error.

I believe that the problem is caused by my Main class being inside a .war file which has no effect on the classpath, which is why it can't be found.

How do I package my project up so it works locally and on my live server?

答案1

得分: 4

我认为你的问题在于你将Main类包含在war文件中,而App Engine 无法找到它。

正如你可以在GCP迁移指南中看到的,Main类定义在名为simple-jetty-main的外部依赖中。

通过执行maven-dependency-plugin,这个依赖会被复制到appengine-staging目录中,从而使它可以从Java类路径中访问到。

这就是为什么在指南中提出的示例中,当执行来自app.yaml的命令时,可以找到Main类:

entrypoint: &#39;java -cp &quot;*&quot; com.example.appengine.demo.jettymain.Main helloworld.war&#39;

因此,解决方案是将你的Main类包含在与需要部署的war文件独立的另一个库中。

也许你可以创建一个库,就像Google在simple-jetty-main中所做的一样,可以在你的GCP项目中重用。

仅仅为了测试,以确认这一点,你可以使用simple-jetty-main库本身(你可以从https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/appengine-java11/appengine-simple-jetty-main克隆所需的代码)。安装它,将依赖项包含在你的pom.xml中,还包括maven-dependency-plugin,并将你的entrypoint定义如下:

entrypoint: &#39;java -cp &quot;*&quot; com.example.appengine.demo.jettymain.Main app-engine-hello-world-1.war&#39;

对于你的评论,你可能不希望在Main类和其他代码之间有分离。

为了满足这个要求,我们首先必须更改Main类,以便Jetty可以为HelloWorldServlet和静态内容提供服务。实际上,代码与你提供的代码非常相似。请原谅设置的简单性,它基于web.xml文件;如果需要的话,可以进一步开发以处理注释或其他合适的内容:

package io.happycoding;

import java.net.URL;

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

public class Main {

  public static final String WEBAPP_RESOURCES_LOCATION = &quot;META-INF/resources&quot;;

  public static void main(String[] args) throws Exception {
    System.setProperty(&quot;org.eclipse.jetty.util.log.class&quot;, &quot;org.eclipse.jetty.util.log.StrErrLog&quot;);
    System.setProperty(&quot;org.eclipse.jetty.LEVEL&quot;, &quot;INFO&quot;);

    Server server = new Server(8080);

    URL webAppDir = Thread.currentThread().getContextClassLoader().getResource(WEBAPP_RESOURCES_LOCATION);
    if (webAppDir == null) {
      throw new RuntimeException(String.format(&quot;Unable to find %s directory into the JAR file&quot;, WEBAPP_RESOURCES_LOCATION));
    }

    WebAppContext webAppContext = new WebAppContext();
    webAppContext.setContextPath(&quot;/&quot;);
    webAppContext.setDescriptor(WEBAPP_RESOURCES_LOCATION + &quot;/WEB-INF/web.xml&quot;);
    webAppContext.setResourceBase(webAppDir.toURI().toString());
    webAppContext.setParentLoaderPriority(true);

    server.setHandler(webAppContext);

    server.start();

    server.join();
  }
}

静态资源可以从你选择的目录加载(它将在pom.xml中参数化)。

例如,我创建了src/main/webapp文件夹来存储静态内容。

在这个文件夹中,你还需要定义一个带有以下web.xml文件的WEB-INF目录(在这种情况下,由于我们设置了Jetty的方式,必须这样做):

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; xmlns:web=&quot;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
         version=&quot;2.5&quot;&gt;

    &lt;servlet&gt;
        &lt;servlet-name&gt;HelloWorldServlet&lt;/servlet-name&gt;
        &lt;servlet-class&gt;io.happycoding.servlets.HelloWorldServlet&lt;/servlet-class&gt;
    &lt;/servlet&gt;

    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;HelloWorldServlet&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/hello&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;

    &lt;welcome-file-list&gt;
        &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;
    &lt;/welcome-file-list&gt;

&lt;/web-app&gt;

这是我的源代码设置的tree

App Engine Java 11 在实际服务器上找不到或加载不了主类。

pom.xml文件与你提供的文件非常相似。我只包括了maven-resources-plugin来将Web应用程序的静态内容复制到jar文件中,并使用maven-shade-plugin来生成UberJar:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;io.happycoding&lt;/groupId&gt;
    &lt;artifactId&gt;app-engine-hello-world&lt;/artifactId&gt;
    &lt;version&gt;1&lt;/version&gt;
    &lt;packaging&gt;jar&lt;/

<details>
<summary>英文:</summary>

I think your problem is that you are including the ```Main``` class in the war itself, and App Engine is unable to find it.

As you can see in the [GCP migration guide](https://cloud.google.com/appengine/docs/standard/java11/java-differences), the ```Main``` class is defined in an external dependency named ```simple-jetty-main```.

With the execution of the ```maven-dependency-plugin``` this dependency is copied to the ```appengine-staging``` directory, making it accessible from the Java classpath.

This is the reason why the ```Main``` class can be found in the example proposed in the guide when executing the command from the ```app.yaml``` ```entrypoint```:

```yaml
entrypoint: &#39;java -cp &quot;*&quot; com.example.appengine.demo.jettymain.Main helloworld.war&#39;

Therefore, the solution will be to include your Main class in another library, independent from the war file that you need to deploy.

Maybe you can create a library - as Google does with simple-jetty-main - that can reuse in your GCP projects for this task.

Just for testing, in order to confirm this point, you can use the simple-jetty-main library itself (you can clone the required code from https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/appengine-java11/appengine-simple-jetty-main). Install it, include the dependency in your pom.xml, include also the maven-dependency-plugin, and define your entrypoint as follows:

entrypoint: &#39;java -cp &quot;*&quot; com.example.appengine.demo.jettymain.Main app-engine-hello-world-1.war&#39;

For your comments, you will prefer not to have the separation between the Main class and the rest of the code.

To meet that requirement we must first change the Main class so that Jetty can serve HelloWorldSevlet and the static content. The code is actually very similar to the one you provided. Please excuse the simplicity of the setup, it is based on web.xml file; if necessary, further development can be done to deal with annotations or whatever is deemed appropriate:

package io.happycoding;

import java.net.URL;

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

public class Main {

  public static final String WEBAPP_RESOURCES_LOCATION = &quot;META-INF/resources&quot;;

  public static void main(String[] args) throws Exception {
    System.setProperty(&quot;org.eclipse.jetty.util.log.class&quot;, &quot;org.eclipse.jetty.util.log.StrErrLog&quot;);
    System.setProperty(&quot;org.eclipse.jetty.LEVEL&quot;, &quot;INFO&quot;);

    Server server = new Server(8080);

    URL webAppDir = Thread.currentThread().getContextClassLoader().getResource(WEBAPP_RESOURCES_LOCATION);
    if (webAppDir == null) {
      throw new RuntimeException(String.format(&quot;Unable to find %s directory into the JAR file&quot;, WEBAPP_RESOURCES_LOCATION));
    }

    WebAppContext webAppContext = new WebAppContext();
    webAppContext.setContextPath(&quot;/&quot;);
    webAppContext.setDescriptor(WEBAPP_RESOURCES_LOCATION + &quot;/WEB-INF/web.xml&quot;);
    webAppContext.setResourceBase(webAppDir.toURI().toString());
    webAppContext.setParentLoaderPriority(true);

    server.setHandler(webAppContext);

    server.start();

    server.join();
  }
}

The static resources can be loaded from a directory of your choice (it will be parameterized in the pom.xml).

For instance, I have created the src/main/webapp folder to store the static content.

In this folder, you also need to define - in this case, due to the way we setup Jetty - a WEB-INF directory with this web.xml file inside:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; xmlns:web=&quot;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;
         version=&quot;2.5&quot;&gt;

    &lt;servlet&gt;
        &lt;servlet-name&gt;HelloWorldServlet&lt;/servlet-name&gt;
        &lt;servlet-class&gt;io.happycoding.servlets.HelloWorldServlet&lt;/servlet-class&gt;
    &lt;/servlet&gt;

    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;HelloWorldServlet&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/hello&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;

    &lt;welcome-file-list&gt;
        &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;
    &lt;/welcome-file-list&gt;

&lt;/web-app&gt;

This is a tree of my source code setup:

App Engine Java 11 在实际服务器上找不到或加载不了主类。

The pom.xml file is very similar to the one you provided. I only included the maven-resources-plugin to copy the web app static content to the jar file, and the maven-shade-plugin to generate an UberJar:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;io.happycoding&lt;/groupId&gt;
    &lt;artifactId&gt;app-engine-hello-world&lt;/artifactId&gt;
    &lt;version&gt;1&lt;/version&gt;
    &lt;packaging&gt;jar&lt;/packaging&gt;

    &lt;properties&gt;
        &lt;!-- App Engine currently supports Java 11 --&gt;
        &lt;maven.compiler.source&gt;11&lt;/maven.compiler.source&gt;
        &lt;maven.compiler.target&gt;11&lt;/maven.compiler.target&gt;
        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
        &lt;failOnMissingWebXml&gt;false&lt;/failOnMissingWebXml&gt;
        &lt;!-- Directory where static content resides --&gt;
        &lt;webapp.dir&gt;./src/main/webapp&lt;/webapp.dir&gt;
    &lt;/properties&gt;

    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
            &lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
            &lt;version&gt;4.0.1&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;dependency&gt;
            &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
            &lt;artifactId&gt;jetty-server&lt;/artifactId&gt;
            &lt;version&gt;9.4.31.v20200723&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
            &lt;artifactId&gt;jetty-webapp&lt;/artifactId&gt;
            &lt;version&gt;9.4.31.v20200723&lt;/version&gt;
            &lt;type&gt;jar&lt;/type&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
            &lt;artifactId&gt;jetty-util&lt;/artifactId&gt;
            &lt;version&gt;9.4.31.v20200723&lt;/version&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
            &lt;artifactId&gt;jetty-annotations&lt;/artifactId&gt;
            &lt;version&gt;9.4.31.v20200723&lt;/version&gt;
            &lt;type&gt;jar&lt;/type&gt;
        &lt;/dependency&gt;

    &lt;/dependencies&gt;

    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
                &lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.0.0&lt;/version&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;java&lt;/goal&gt;
                        &lt;/goals&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
                &lt;configuration&gt;
                    &lt;mainClass&gt;io.happycoding.Main&lt;/mainClass&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;

            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-resources-plugin&lt;/artifactId&gt;
                &lt;version&gt;2.7&lt;/version&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;id&gt;copy-web-resources&lt;/id&gt;
                        &lt;phase&gt;compile&lt;/phase&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;copy-resources&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;configuration&gt;
                            &lt;outputDirectory&gt;${project.build.directory}/classes/META-INF/resources&lt;/outputDirectory&gt;
                            &lt;resources&gt;
                                &lt;resource&gt;
                                    &lt;directory&gt;${webapp.dir}&lt;/directory&gt;
                                &lt;/resource&gt;
                            &lt;/resources&gt;
                        &lt;/configuration&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
            &lt;/plugin&gt;

            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.2.4&lt;/version&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;phase&gt;package&lt;/phase&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;shade&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;configuration&gt;
                            &lt;transformers&gt;
                                &lt;transformer implementation=&quot;org.apache.maven.plugins.shade.resource.ManifestResourceTransformer&quot;&gt;
                                    &lt;mainClass&gt;io.happycoding.Main&lt;/mainClass&gt;
                                &lt;/transformer&gt;
                            &lt;/transformers&gt;
                        &lt;/configuration&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
            &lt;/plugin&gt;

            &lt;plugin&gt;
              &lt;groupId&gt;com.google.cloud.tools&lt;/groupId&gt;
              &lt;artifactId&gt;appengine-maven-plugin&lt;/artifactId&gt;
              &lt;version&gt;2.2.0&lt;/version&gt;
              &lt;configuration&gt;
                &lt;projectId&gt;happy-coding-gcloud&lt;/projectId&gt;
                &lt;version&gt;1&lt;/version&gt;
              &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;


&lt;/project&gt;

With this setup, you can run the application locally by executing the following command:

mvn exec:java

You can also run the program locally right from the java tool:

java -jar appengine-deploy-sample-1.jar

Sorry, I cannot test the setup in GCP but I think, that according to the migration guide, you can try to deploy the application without indicating the entrypoint in your app.yaml.

If it does not work, you can try to run the app by configuring an entrypoint similar to the following:

entrypoint: &#39;java -jar appengine-deploy-sample-1.jar&#39;

Or maybe:

entrypoint: &#39;java -cp &quot;*&quot; -jar appengine-deploy-sample-1.jar&#39;

huangapple
  • 本文由 发表于 2020年8月10日 09:42:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/63333073.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定