Disable Tomcat’s reference clearing

Closes gh-15101
This commit is contained in:
Andy Wilkinson 2019-01-11 10:34:14 +00:00
parent 82a77a351a
commit 6307cb5943
5 changed files with 79 additions and 4 deletions

View File

@ -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.
}
}
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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();