Respect Tomcat's failCtxIfServletStartFails flag
Ensure that if the user has set `failCtxIfServletStartFails` to `true` using a `ContextCustomizers` any Servlet init exceptions stop the application from running. Closes gh-14448
This commit is contained in:
parent
042d495d92
commit
21ebb94d49
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2017 the original author or authors.
|
* Copyright 2012-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -17,10 +17,12 @@
|
||||||
package org.springframework.boot.web.embedded.tomcat;
|
package org.springframework.boot.web.embedded.tomcat;
|
||||||
|
|
||||||
import org.apache.catalina.Container;
|
import org.apache.catalina.Container;
|
||||||
|
import org.apache.catalina.LifecycleException;
|
||||||
import org.apache.catalina.Manager;
|
import org.apache.catalina.Manager;
|
||||||
import org.apache.catalina.core.StandardContext;
|
import org.apache.catalina.core.StandardContext;
|
||||||
import org.apache.catalina.session.ManagerBase;
|
import org.apache.catalina.session.ManagerBase;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
@ -59,7 +61,7 @@ class TomcatEmbeddedContext extends StandardContext {
|
||||||
super.setManager(manager);
|
super.setManager(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deferredLoadOnStartup() {
|
public void deferredLoadOnStartup() throws LifecycleException {
|
||||||
// Some older Servlet frameworks (e.g. Struts, BIRT) use the Thread context class
|
// Some older Servlet frameworks (e.g. Struts, BIRT) use the Thread context class
|
||||||
// loader to create servlet instances in this phase. If they do that and then try
|
// loader to create servlet instances in this phase. If they do that and then try
|
||||||
// to initialize them later the class loader may have changed, so wrap the call to
|
// to initialize them later the class loader may have changed, so wrap the call to
|
||||||
|
@ -70,15 +72,20 @@ class TomcatEmbeddedContext extends StandardContext {
|
||||||
if (classLoader != null) {
|
if (classLoader != null) {
|
||||||
existingLoader = ClassUtils.overrideThreadContextClassLoader(classLoader);
|
existingLoader = ClassUtils.overrideThreadContextClassLoader(classLoader);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
if (this.overrideLoadOnStart) {
|
if (this.overrideLoadOnStart) {
|
||||||
// Earlier versions of Tomcat used a version that returned void. If that
|
// Earlier versions of Tomcat used a version that returned void. If that
|
||||||
// version is used our overridden loadOnStart method won't have been called
|
// version is used our overridden loadOnStart method won't have been
|
||||||
// and the original will have already run.
|
// called and the original will have already run.
|
||||||
super.loadOnStartup(findChildren());
|
boolean started = super.loadOnStartup(findChildren());
|
||||||
|
Assert.state(started,
|
||||||
|
"Unable to start embedded tomcat context " + getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (existingLoader != null) {
|
finally {
|
||||||
ClassUtils.overrideThreadContextClassLoader(existingLoader);
|
if (existingLoader != null) {
|
||||||
|
ClassUtils.overrideThreadContextClassLoader(existingLoader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,10 +223,15 @@ public class TomcatWebServer implements WebServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkThatConnectorsHaveStarted() {
|
private void checkThatConnectorsHaveStarted() {
|
||||||
|
checkConnectorHasStarted(this.tomcat.getConnector());
|
||||||
for (Connector connector : this.tomcat.getService().findConnectors()) {
|
for (Connector connector : this.tomcat.getService().findConnectors()) {
|
||||||
if (LifecycleState.FAILED.equals(connector.getState())) {
|
checkConnectorHasStarted(connector);
|
||||||
throw new ConnectorStartFailedException(connector.getPort());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkConnectorHasStarted(Connector connector) {
|
||||||
|
if (LifecycleState.FAILED.equals(connector.getState())) {
|
||||||
|
throw new ConnectorStartFailedException(connector.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.Set;
|
||||||
import javax.naming.InitialContext;
|
import javax.naming.InitialContext;
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
|
||||||
import org.apache.catalina.Container;
|
import org.apache.catalina.Container;
|
||||||
import org.apache.catalina.Context;
|
import org.apache.catalina.Context;
|
||||||
|
@ -41,6 +42,7 @@ import org.apache.catalina.SessionIdGenerator;
|
||||||
import org.apache.catalina.Valve;
|
import org.apache.catalina.Valve;
|
||||||
import org.apache.catalina.connector.Connector;
|
import org.apache.catalina.connector.Connector;
|
||||||
import org.apache.catalina.core.AprLifecycleListener;
|
import org.apache.catalina.core.AprLifecycleListener;
|
||||||
|
import org.apache.catalina.core.StandardContext;
|
||||||
import org.apache.catalina.core.StandardWrapper;
|
import org.apache.catalina.core.StandardWrapper;
|
||||||
import org.apache.catalina.startup.Tomcat;
|
import org.apache.catalina.startup.Tomcat;
|
||||||
import org.apache.catalina.util.CharsetMapper;
|
import org.apache.catalina.util.CharsetMapper;
|
||||||
|
@ -427,6 +429,21 @@ public class TomcatServletWebServerFactoryTests
|
||||||
assertThat(context.getUseHttpOnly()).isFalse();
|
assertThat(context.getUseHttpOnly()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exceptionThrownOnLoadFailureWhenFailCtxIfServletStartFailsIsTrue() {
|
||||||
|
TomcatServletWebServerFactory factory = getFactory();
|
||||||
|
factory.addContextCustomizers((context) -> {
|
||||||
|
if (context instanceof StandardContext) {
|
||||||
|
((StandardContext) context).setFailCtxIfServletStartFails(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.webServer = factory.getWebServer((context) -> {
|
||||||
|
context.addServlet("failing", FailingServlet.class).setLoadOnStartup(0);
|
||||||
|
});
|
||||||
|
this.thrown.expect(WebServerException.class);
|
||||||
|
this.webServer.start();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JspServlet getJspServlet() throws ServletException {
|
protected JspServlet getJspServlet() throws ServletException {
|
||||||
Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();
|
Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();
|
||||||
|
@ -475,4 +492,13 @@ public class TomcatServletWebServerFactoryTests
|
||||||
assertThat(((ConnectorStartFailedException) ex).getPort()).isEqualTo(blockedPort);
|
assertThat(((ConnectorStartFailedException) ex).getPort()).isEqualTo(blockedPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class FailingServlet extends HttpServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws ServletException {
|
||||||
|
throw new RuntimeException("Init Failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue