diff --git a/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java b/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java index 01bf46eb56c..019f11b2d17 100644 --- a/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java +++ b/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatWebServer.java @@ -94,6 +94,9 @@ public class TomcatWebServer implements WebServer { // Start the server to trigger initialization listeners this.tomcat.start(); + // We can re-throw failure exception directly in the main thread + rethrowDeferredStartupExceptions(); + Context context = findContext(); try { ContextBindings.bindClassLoader(context, context.getNamingToken(), @@ -140,6 +143,25 @@ public class TomcatWebServer implements WebServer { } } + private void rethrowDeferredStartupExceptions() throws Exception { + Container[] children = this.tomcat.getHost().findChildren(); + for (Container container : children) { + if (container instanceof TomcatEmbeddedContext) { + TomcatStarter tomcatStarter = ((TomcatEmbeddedContext) container) + .getStarter(); + if (tomcatStarter != null) { + Exception exception = tomcatStarter.getStartUpException(); + if (exception != null) { + throw exception; + } + } + } + if (!LifecycleState.STARTED.equals(container.getState())) { + throw new IllegalStateException(container + " failed to start"); + } + } + } + private void startDaemonAwaitThread() { Thread awaitThread = new Thread("container-" + (containerCounter.get())) { diff --git a/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java index ddc4b0f3572..39d88af3bee 100644 --- a/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactoryTests.java @@ -23,7 +23,13 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -45,6 +51,8 @@ import org.mockito.InOrder; import org.springframework.boot.web.server.Compression; import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.WebServerException; +import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactoryTests; @@ -277,6 +285,38 @@ public class JettyServletWebServerFactoryTests .isSameAs(threadPool); } + @Test + public void faultyFilterCausesStartFailure() throws Exception { + JettyServletWebServerFactory factory = getFactory(); + factory.addInitializers(new ServletContextInitializer() { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + servletContext.addFilter("faulty", new Filter() { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + throw new ServletException("Faulty filter"); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + + }); + } + + }); + this.thrown.expect(WebServerException.class); + factory.getWebServer().start(); + } + @Override @SuppressWarnings("serial") // Workaround for Jetty issue - https://bugs.eclipse.org/bugs/show_bug.cgi?id=470646 diff --git a/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java index 8dd392b8010..f96af9f9c13 100644 --- a/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java @@ -26,7 +26,13 @@ import java.util.concurrent.TimeUnit; import javax.naming.InitialContext; import javax.naming.NamingException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import org.apache.catalina.Container; import org.apache.catalina.Context; @@ -51,6 +57,7 @@ import org.mockito.InOrder; import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.WebServerException; +import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactoryTests; import org.springframework.test.util.ReflectionTestUtils; @@ -444,6 +451,38 @@ public class TomcatServletWebServerFactoryTests assertThat(sessionIdGenerator.getJvmRoute()).isEqualTo("test"); } + @Test + public void faultyFilterCausesStartFailure() throws Exception { + TomcatServletWebServerFactory factory = getFactory(); + factory.addInitializers(new ServletContextInitializer() { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + servletContext.addFilter("faulty", new Filter() { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + throw new ServletException("Faulty filter"); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + + }); + } + + }); + this.thrown.expect(WebServerException.class); + factory.getWebServer().start(); + } + @Override protected JspServlet getJspServlet() throws ServletException { Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();