From 6307cb59439c5cc85878262a703a025e8490feb5 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 11 Jan 2019 10:34:14 +0000 Subject: [PATCH] =?UTF-8?q?Disable=20Tomcat=E2=80=99s=20reference=20cleari?= =?UTF-8?q?ng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes gh-15101 --- ...bleReferenceClearingContextCustomizer.java | 47 +++++++++++++++++++ .../TomcatReactiveWebServerFactory.java | 3 +- .../tomcat/TomcatServletWebServerFactory.java | 3 +- .../TomcatReactiveWebServerFactoryTests.java | 16 ++++++- .../TomcatServletWebServerFactoryTests.java | 14 +++++- 5 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/DisableReferenceClearingContextCustomizer.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/DisableReferenceClearingContextCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/DisableReferenceClearingContextCustomizer.java new file mode 100644 index 00000000000..b19a51c55ad --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/DisableReferenceClearingContextCustomizer.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.web.embedded.tomcat; + +import org.apache.catalina.Context; +import org.apache.catalina.core.StandardContext; + +/** + * A {@link TomcatContextCustomizer} that disables Tomcat's reflective reference clearing + * to avoid reflective access warnings on Java 9 and later JVMs. + * + * @author Andy Wilkinson + */ +class DisableReferenceClearingContextCustomizer implements TomcatContextCustomizer { + + @Override + public void customize(Context context) { + if (!(context instanceof StandardContext)) { + return; + } + StandardContext standardContext = (StandardContext) context; + try { + standardContext.setClearReferencesObjectStreamClassCaches(false); + standardContext.setClearReferencesRmiTargets(false); + standardContext.setClearReferencesThreadLocals(false); + } + catch (NoSuchMethodError ex) { + // Earlier version of Tomcat (probably without + // setClearReferencesThreadLocals). Continue. + } + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java index b76f1f37bd6..4fcb46aa7ae 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -149,6 +149,7 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac */ protected void configureContext(Context context) { this.contextLifecycleListeners.forEach(context::addLifecycleListener); + new DisableReferenceClearingContextCustomizer().customize(context); this.tomcatContextCustomizers .forEach((customizer) -> customizer.customize(context)); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java index c7e4cebb391..d6422268f01 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -347,6 +347,7 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto context.addMimeMapping(mapping.getExtension(), mapping.getMimeType()); } configureSession(context); + new DisableReferenceClearingContextCustomizer().customize(context); for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) { customizer.customize(context); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java index 342e7de0a03..202de1b0290 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.connector.Connector; import org.apache.catalina.core.AprLifecycleListener; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.startup.Tomcat; import org.apache.catalina.valves.RemoteIpValve; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -138,4 +140,16 @@ public class TomcatReactiveWebServerFactoryTests assertForwardHeaderIsUsed(factory); } + @Test + public void referenceClearingIsDisabled() { + TomcatReactiveWebServerFactory factory = getFactory(); + this.webServer = factory.getWebServer(mock(HttpHandler.class)); + this.webServer.start(); + Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat(); + StandardContext context = (StandardContext) tomcat.getHost().findChildren()[0]; + assertThat(context.getClearReferencesObjectStreamClassCaches()).isFalse(); + assertThat(context.getClearReferencesRmiTargets()).isFalse(); + assertThat(context.getClearReferencesThreadLocals()).isFalse(); + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java index 0518ad2ab35..487d12f7c26 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -451,6 +451,18 @@ public class TomcatServletWebServerFactoryTests this.webServer.start(); } + @Test + public void referenceClearingIsDisabled() { + TomcatServletWebServerFactory factory = getFactory(); + this.webServer = factory.getWebServer(); + this.webServer.start(); + Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat(); + StandardContext context = (StandardContext) tomcat.getHost().findChildren()[0]; + assertThat(context.getClearReferencesObjectStreamClassCaches()).isFalse(); + assertThat(context.getClearReferencesRmiTargets()).isFalse(); + assertThat(context.getClearReferencesThreadLocals()).isFalse(); + } + @Override protected JspServlet getJspServlet() throws ServletException { Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();