diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java index 90810cb4a95..2f60bcba54b 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java @@ -20,6 +20,8 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import javax.naming.NamingException; + import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; @@ -30,6 +32,7 @@ import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.naming.ContextBindings; import org.springframework.boot.context.embedded.EmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainerException; @@ -93,8 +96,14 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer // We can re-throw failure exception directly in the main thread rethrowDeferredStartupExceptions(); - ClassLoader classLoader = findContext().getLoader().getClassLoader(); - Thread.currentThread().setContextClassLoader(classLoader); + Context context = findContext(); + try { + ContextBindings.bindClassLoader(context, context.getNamingToken(), + getClass().getClassLoader()); + } + catch (NamingException ex) { + // Naming is not enabled. Continue + } // Unlike Jetty, all Tomcat threads are daemon threads. We create a // blocking non-daemon to stop immediate shutdown @@ -180,6 +189,11 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer throw new EmbeddedServletContainerException( "Unable to start embedded Tomcat servlet container", ex); } + finally { + Context context = findContext(); + ContextBindings.unbindClassLoader(context, context.getNamingToken(), + getClass().getClassLoader()); + } } private void checkThatConnectorsHaveStarted() { diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java index c29b7a055b1..2b57c02b096 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java @@ -24,6 +24,9 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; +import javax.naming.InitialContext; +import javax.naming.NamingException; + import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.LifecycleEvent; @@ -399,14 +402,34 @@ public class TomcatEmbeddedServletContainerFactoryTests } @Test - public void tcclOfMainThreadIsTomcatWebAppClassLoader() { + public void jndiLookupsCanBePerformedDuringApplicationContextRefresh() + throws NamingException { Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); - TomcatEmbeddedServletContainerFactory factory = getFactory(); + TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory( + 0) { + + @Override + protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer( + Tomcat tomcat) { + tomcat.enableNaming(); + return super.getTomcatEmbeddedServletContainer(tomcat); + } + + }; + + // Container is created in onRefresh this.container = factory.getEmbeddedServletContainer(); + + // Lookups should now be possible + new InitialContext().lookup("java:comp/env"); + + // Called in finishRefresh, giving us an opportunity to remove the context binding + // and avoid a leak this.container.start(); - assertThat(Thread.currentThread().getContextClassLoader()) - .isInstanceOf(TomcatEmbeddedWebappClassLoader.class); - this.container.stop(); + + // Lookups should no longer be possible + this.thrown.expect(NamingException.class); + new InitialContext().lookup("java:comp/env"); } @Override