App Engine Java 11 Gradle - 无法在生产中加载主类

问题描述 投票:0回答:0

我目前正致力于将一个 Java 8 App Engine 项目迁移到 Java 11,正如在 Google 的迁移指南中 所记录的那样。许多示例和文档都集中在 Maven 上,我已经将我能做的调整到 Gradle 并完成了大部分工作。但是,我面临着让部署的代码找到项目打包的嵌入式 Jetty 服务器的主类的问题。

我可以通过执行以下命令的内联“运行”工具在 Visual Studio 代码中本地运行项目:

C:\\Program\ Files\\Eclipse\ Adoptium\\jdk-11.0.18.10-hotspot\\bin\\java.exe -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=localhost:56132 @C:\\Users\\test\\AppData\\Local\\Temp\\cp_dz6hms01lt5nflua2xbcqzqr4.argfile com.example.server.ServerMain 

这与谷歌的 repackaging guides 之一以及执行战争时记录的内容相符。上面命令中引用的 argfile 似乎只列出了项目中使用的所有库和依赖项。

java -cp "*" com.example.appengine.demo.jettymain.Main helloworld.war

所有端点都按预期工作,我什至能够毫无问题地将代码部署到 App Engine。

非常类似于这个问题一旦部署了代码,它就无法使用指定的入口点加载主类。我意识到这听起来像是一个重复的问题,但从 Maven 到 Gradle 的感觉不同足以引起一些严重的头痛。

App.yaml

runtime: java11
entrypoint: 'java -cp "*" com.example.server.ServerMain server.war'

查看上述问题的答案,建议的解决方案是修改 maven 构建脚本以将项目打包到 jar 中,并修改入口点以像启动任何其他 jar 一样启动 Web 服务器。但是,使用 App Engine Gradle 插件时,不会生成 jar,而是执行 war 任务。此外,当我手动去本地运行 shadowJar 时,永远无法访问网络服务器进行测试。所以我相信这个解决方案可能不适用于基于 Gradle 的项目。

我试图强制战争在 build.gradle 中包含所需的清单信息,但没有成功。生成了预期的清单,但由于这是一场战争,它似乎仍然不想执行。

war {
  webInf { from 'src/main/appengine'}
  manifest {
    attributes(
      'Main-Class': 'com.example.server.ServerMain'
    )
  }
}

清单.MF

Manifest-Version: 1.0
Main-Class: com.example.server.ServerMain

我觉得“java -cp”入口点的一些变体应该可以工作,因为我能够在本地运行类似的东西,但我对 java 标志没有太多经验,也不确定从这里去哪里。

附加信息

我会使用 appengine-simple-jetty-main 外部 Jetty 库,如here 所用。但是,我正在运行一个嵌入式码头服务器,因为我有一个我认为不会正确应用的自定义资源配置。

ServerMain.java

import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.jetty.server.Server;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;

public class ServerMain {
    public static void main(String[] args) throws Exception {
        try {
            ResourceConfig config = new App();
            Server server = JettyHttpContainerFactory.createServer(URI.create("http://0.0.0.0:8080/"), config);

            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try  {
                    System.out.println("Shutting down the application...");
                    server.stop();
                    System.out.println("Done, exit.");
                } catch (Exception e) {
                    Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, e);
                }
            }));

            Thread.currentThread().join();
        } catch (InterruptedException ex) {
            Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

App.java


@ApplicationPath("/*")
public class App extends ResourceConfig {
    private static final Logger log = Logger.getLogger(App.class.getName());

    public App() {
        packages("com.example.server.handlers",  "com.example.server.filters", "com.example.server.interceptors");
        register(GsonJerseyProvider.class);
        register(MultiPartFeature.class);

        Sentry.init(options -> {
            options.setDsn(System.getenv("SENTRY_URL"));
        });

        try {
            FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(GoogleCredentials.getApplicationDefault())
                .setDatabaseUrl(System.getenv("FIREBASE_URL"))
                .build();

            FirebaseApp.initializeApp(options);
        } catch (IllegalStateException e) {
            log.severe(e.getMessage());
            Sentry.captureException(e);
        } catch (IOException e) {
            log.severe(e.getMessage());
            Sentry.captureException(e);
        }
    }
}

所以我的问题是,如何将 Gradle 项目打包到一个 war/jar 中,既可以在本地执行又可以通过“appengineDeploy”任务部署?

java gradle google-app-engine google-cloud-platform webserver
© www.soinside.com 2019 - 2024. All rights reserved.