Jetty 无法启动 spring 灵活的 App Engine 中的启动应用程序

Jetty fails to start spring boot application in appengine flexible

注意:这是一个交叉 post 因为我不确定这是技术问题还是错误所以可以找到错误 here

几周前,我编写了一个原型,用于将灵活的环境服务添加到我们的应用引擎项目中,该项目主要是标准环境服务。该原型基于 java 快速入门示例 "HelloworldSpringBoot",并进行了一些小的修改。

在我的原型成功后,我转移到该服务的更多生产代码集,开发它几个星期并尝试在 4 天前的 1 月 12 日部署。该应用程序拒绝启动,在多次尝试将应用程序简化为单一路径后,我无法启动该应用程序。

我切换回原型代码,部署到该代码正在运行的原始项目中,我看到应用未启动的相同行为。

没有可指出的错误消息,因此我将在此处列出一对可能是罪魁祸首的错误消息。

第一个是最明显的,但可能是一个通用的包罗万象:

Exception in thread "main" java.lang.IllegalStateException: No Available Context
        at com.google.cloud.runtimes.jetty9.DeploymentCheck.lifeCycleStarted(DeploymentCheck.java:46)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.setStarted(AbstractLifeCycle.java:179)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
        at org.eclipse.jetty.xml.XmlConfiguration.run(XmlConfiguration.java:1511)
        at org.eclipse.jetty.xml.XmlConfiguration.run(XmlConfiguration.java:1438)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1437)

下一个发生在启动的早期,但似乎是良性的:

javax.servlet.ServletException: Not running on Jetty, JSR-356 support unavailable at org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.onStartup(WebSocketServerContainerInitializer.java:193) at org.eclipse.jetty.plus.annotation.ContainerInitializer.callStartup(ContainerInitializer.java:140) at org.eclipse.jetty.annotations.ServletContainerInitializersStarter.doStart(ServletContainerInitializersStarter.java:63) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:329) at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1501) at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1463) at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:785) at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:261) at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:545) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:41) at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:188) at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:502) at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:150) at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:180) at org.eclipse.jetty.deploy.providers.WebAppProvider.fileAdded(WebAppProvider.java:447) at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:64) at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:610) at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:529) at org.eclipse.jetty.util.Scanner.scan(Scanner.java:392) at org.eclipse.jetty.util.Scanner.doStart(Scanner.java:313) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.deploy.providers.ScanningAppProvider.doStart(ScanningAppProvider.java:150) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.deploy.DeploymentManager.startAppProvider(DeploymentManager.java:564) at org.eclipse.jetty.deploy.DeploymentManager.doStart(DeploymentManager.java:239) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131) at org.eclipse.jetty.server.Server.start(Server.java:452) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113) at org.eclipse.jetty.server.Server.doStart(Server.java:419) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.xml.XmlConfiguration.run(XmlConfiguration.java:1511) at org.eclipse.jetty.xml.XmlConfiguration.run(XmlConfiguration.java:1438) at java.security.AccessController.doPrivileged(Native Method) at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1437)

然后是紧接在前一个之后的这个人:

org.eclipse.jetty.webapp.WebAppContext: Failed startup of context o.e.j.w.WebAppContext@7e0b0338{/,file:///var/lib/jetty/webapps/root/,UNAVAILABLE}{/root.war}

此外,以下是相关文件:

app.yaml:

runtime: java
env: flex

runtime_config:  # Optional
  jdk: openjdk8

service: service2

handlers:
- url: /.*
  script: this field is required, but ignored

manual_scaling:
  instances: 1

build.gradle:

buildscript {      // Configuration for building
    ext {
        springBootVersion = '1.5.9.RELEASE'
    }
    repositories {
        jcenter()      // Bintray's repository - a fast Maven Central mirror & more
        mavenCentral()
        maven { url 'https://repo.spring.io/libs-snapshot' }
    }
    dependencies {
        classpath 'com.google.cloud.tools:appengine-gradle-plugin:+'
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
    }
}

repositories {   // repositories for JARs you access in your code
    maven {
        url 'https://maven-central.storage.googleapis.com'             // Google's mirror of Maven Central
    }

    maven {
        url "http://repo.spring.io/libs-snapshot"
    }

    jcenter()
    mavenCentral()
}

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'com.google.cloud.tools.appengine'
apply plugin: 'org.springframework.boot'

dependencies {

    // Add your dependencies here.
    compile "org.springframework.boot:spring-boot-starter-web", { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' }
    compile (
            "org.springframework.boot:spring-boot-starter-actuator",
            "org.springframework.boot:spring-boot-starter-jetty"
    )
    testCompile (
            "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
    )

}

appengine {

    deploy {   // deploy configuration
        stopPreviousVersion = true  // default - stop the current version
        promote = true              // default - & make this the current version
    }

}

group = 'com.example'   // Generated output GroupId
version = '1.0-SNAPSHOT'          // Version in generated output

sourceCompatibility = 1.8
targetCompatibility = 1.8

HelloworldApplication.java:

package com.example.java.gettingstarted;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class HelloworldApplication {
  @RequestMapping("/service2/")
  public String home() {
    return "Helloooooooo Nurse!";
  }

  /**
   * (Optional) App Engine health check endpoint mapping.
   * @see <a href="https://cloud.google.com/appengine/docs/flexible/java/how-instances-are-managed#health_checking"></a>
   * If your app does not handle health checks, a HTTP 404 response is interpreted
   *     as a successful reply.
   */
  @RequestMapping("/_ah/health")
  public String healthy() {
    // Message body required though ignored
    return "Still surviving.";
  }

  public static void main(String[] args) {
    SpringApplication.run(HelloworldApplication.class, args);
  }
}

我也是运行gcloud版本184.0.0

解决方案最终有点神奇,但是一旦 Appengine 标准文档为我指明了正确的方向,SpringBoot documentation 就告诉了我。

Note that a WebApplicationInitializer is only needed if you are building a war file and deploying it. If you prefer to run an embedded container then you won't need this at all.

我们正在部署 war 并且在本地是 运行 嵌入式容器。按照提供的方式设置 jetty 并将神奇的 SpringBootServletInitializer 添加到根目录后,事情开始起作用了。我不知道为什么两周前不需要,但现在肯定需要。

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        System.out.println("ServletInitializer called.");
        return application.sources(HelloworldApplication.class);
    }
} 

将这个文件放在根目录下就可以了。

感谢您的帮助。