Skip to content

Commit 6307cb5

Browse files
committed
Disable Tomcat’s reference clearing
Closes gh-15101
1 parent 82a77a3 commit 6307cb5

File tree

5 files changed

+79
-4
lines changed

5 files changed

+79
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.web.embedded.tomcat;
18+
19+
import org.apache.catalina.Context;
20+
import org.apache.catalina.core.StandardContext;
21+
22+
/**
23+
* A {@link TomcatContextCustomizer} that disables Tomcat's reflective reference clearing
24+
* to avoid reflective access warnings on Java 9 and later JVMs.
25+
*
26+
* @author Andy Wilkinson
27+
*/
28+
class DisableReferenceClearingContextCustomizer implements TomcatContextCustomizer {
29+
30+
@Override
31+
public void customize(Context context) {
32+
if (!(context instanceof StandardContext)) {
33+
return;
34+
}
35+
StandardContext standardContext = (StandardContext) context;
36+
try {
37+
standardContext.setClearReferencesObjectStreamClassCaches(false);
38+
standardContext.setClearReferencesRmiTargets(false);
39+
standardContext.setClearReferencesThreadLocals(false);
40+
}
41+
catch (NoSuchMethodError ex) {
42+
// Earlier version of Tomcat (probably without
43+
// setClearReferencesThreadLocals). Continue.
44+
}
45+
}
46+
47+
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -149,6 +149,7 @@ private void skipAllTldScanning(TomcatEmbeddedContext context) {
149149
*/
150150
protected void configureContext(Context context) {
151151
this.contextLifecycleListeners.forEach(context::addLifecycleListener);
152+
new DisableReferenceClearingContextCustomizer().customize(context);
152153
this.tomcatContextCustomizers
153154
.forEach((customizer) -> customizer.customize(context));
154155
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -347,6 +347,7 @@ protected void configureContext(Context context,
347347
context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
348348
}
349349
configureSession(context);
350+
new DisableReferenceClearingContextCustomizer().customize(context);
350351
for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) {
351352
customizer.customize(context);
352353
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,8 @@
2323
import org.apache.catalina.LifecycleListener;
2424
import org.apache.catalina.connector.Connector;
2525
import org.apache.catalina.core.AprLifecycleListener;
26+
import org.apache.catalina.core.StandardContext;
27+
import org.apache.catalina.startup.Tomcat;
2628
import org.apache.catalina.valves.RemoteIpValve;
2729
import org.junit.Test;
2830
import org.mockito.ArgumentCaptor;
@@ -138,4 +140,16 @@ public void useForwardedHeaders() {
138140
assertForwardHeaderIsUsed(factory);
139141
}
140142

143+
@Test
144+
public void referenceClearingIsDisabled() {
145+
TomcatReactiveWebServerFactory factory = getFactory();
146+
this.webServer = factory.getWebServer(mock(HttpHandler.class));
147+
this.webServer.start();
148+
Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();
149+
StandardContext context = (StandardContext) tomcat.getHost().findChildren()[0];
150+
assertThat(context.getClearReferencesObjectStreamClassCaches()).isFalse();
151+
assertThat(context.getClearReferencesRmiTargets()).isFalse();
152+
assertThat(context.getClearReferencesThreadLocals()).isFalse();
153+
}
154+
141155
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -451,6 +451,18 @@ public void exceptionThrownOnLoadFailureWhenFailCtxIfServletStartFailsIsFalse()
451451
this.webServer.start();
452452
}
453453

454+
@Test
455+
public void referenceClearingIsDisabled() {
456+
TomcatServletWebServerFactory factory = getFactory();
457+
this.webServer = factory.getWebServer();
458+
this.webServer.start();
459+
Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();
460+
StandardContext context = (StandardContext) tomcat.getHost().findChildren()[0];
461+
assertThat(context.getClearReferencesObjectStreamClassCaches()).isFalse();
462+
assertThat(context.getClearReferencesRmiTargets()).isFalse();
463+
assertThat(context.getClearReferencesThreadLocals()).isFalse();
464+
}
465+
454466
@Override
455467
protected JspServlet getJspServlet() throws ServletException {
456468
Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();

0 commit comments

Comments
 (0)