dsyer / spring-boot-legacy

Support for legacy (Servlet 2.5) apps in Spring Boot
99 stars 58 forks source link

Fails on startup in GAE with Spring Boot 2.0 #25

Open dsyer opened 6 years ago

dsyer commented 6 years ago

The war file looks OK but you can see lots of issues in logs (class not found for slf4j for instance). Now that master is tracking Spring Boot 2.0 (thanks to #24) it would be helpful if anyone has time to fix this and send a PR.

ddcruver commented 6 years ago

It was missing the SLF4J API dependency, I have a fix for you but working on trying to resolve some other issues. Spring Boot Legacy seems to work now for the "Spring Boot dependencies are not in WAR" use case but has issues initializing everything in the Google App Engine with 2.5 Servlet.

Google App Engine 2.5 Issues:

Is Google App Engine 2.5 the original purpose of this library? Or is it just the way you choose to test running in a 2.5 servlet container.

dsyer commented 6 years ago

The original purpose was to support Servlet 2.5. Google App Engine was an example of such a platform (with some more extreme constraints). Is it possible to use Servlet 3.1 on App Engine Classic now (if so we can remove that as a goal)?

ddcruver commented 6 years ago

They have a Java 8 Runtime which among having less constraints than the Java 7 Runtime does support Servlet 3.1.

Supports the Java Servlet 3.1 and Java Servlet 2.5 specifications https://cloud.google.com/appengine/docs/standard/java/runtime-java8

Also the Java 7 Runtime is deprecated and will be shutdown January 16, 2019 (https://cloud.google.com/appengine/docs/deprecations/java7).

Additionally since Spring Boot 2.0.X requires Java 8+ there isn't much reason to test running in a Java 7 "container".

I am sure their are environments out there but it would be hard to find an environment that is Java 8, but is not running Servlet 3.0+.

ddcruver commented 6 years ago

I want to do some additional testing with our use case "Spring Boot and Spring Framework not in WAR" and will issues a pull request when I am satisfied.

ddcruver commented 6 years ago

It appears I have everything working for the most part.

In only our use case there is an issue where the /actuator/mappings endpoint gets the dispatcherServlet under $.contexts.application.mappings.servlets but not under $.contexts.application.mappings.dispatcherServlets but nothing seems to be effected by that. Metrics and Security seem to be working just fine.

{
  "contexts": {
    "application": {
      "mappings": {
        "dispatcherServlets": {
          "dispatcherServlet": []
        },
        "servletFilters": [
          {
            "urlPatternMappings": [
              "/*"
            ],
            "servletNameMappings": [],
            "name": "requestContextFilter",
            "className": "org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter"
          },
          {
            "urlPatternMappings": [
              "/*",
              "/*"
            ],
            "servletNameMappings": [],
            "name": "webMvcMetricsFilter",
            "className": "org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter"
          },
          {
            "urlPatternMappings": [
              "/*"
            ],
            "servletNameMappings": [],
            "name": "httpPutFormContentFilter",
            "className": "org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter"
          },
          {
            "urlPatternMappings": [
              "/*"
            ],
            "servletNameMappings": [],
            "name": "hiddenHttpMethodFilter",
            "className": "org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter"
          },
          {
            "urlPatternMappings": [
              "/*"
            ],
            "servletNameMappings": [],
            "name": "characterEncodingFilter",
            "className": "org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter"
          },
          {
            "urlPatternMappings": [
              "/*"
            ],
            "servletNameMappings": [],
            "name": "httpTraceFilter",
            "className": "org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter"
          },
          {
            "urlPatternMappings": [
              "/*",
              "/*",
              "/*"
            ],
            "servletNameMappings": [],
            "name": "springSecurityFilterChain",
            "className": "org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean$1"
          },
          {
            "urlPatternMappings": [],
            "servletNameMappings": [],
            "name": "Undertow Web Socket Filter",
            "className": "io.undertow.websockets.jsr.JsrWebSocketFilter"
          }
        ],
        "servlets": [
          {
            "mappings": [],
            "name": "default",
            "className": "io.undertow.servlet.handlers.DefaultServlet"
          },
          {
            "mappings": [
              "*.jsp",
              "*.jspx"
            ],
            "name": "jsp",
            "className": "org.apache.jasper.servlet.JspServlet"
          },
          {
            "mappings": [
              "/"
            ],
            "name": "dispatcherServlet",
            "className": "org.springframework.web.servlet.DispatcherServlet"
          }
        ]
      },
      "parentId": null
    }
  }
}
ddcruver commented 6 years ago

It appears the problem with our use case only happens when dispatcherServlet is defined in web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>org.example.app.web1.Application</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextAttribute</param-name>
            <param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

But if the web.xml does not contain the dispatcherServlet it works fine.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>org.example.app.web1.Application</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class>
    </listener>
</web-app>