Add property 'server.tomcat.use-apr' to control Tomcat's APR
The property's default depends on the Java version. On Java < 24, it defaults to WHEN_AVAILABLE, on Java >=24 it defaults to NEVER. Closes gh-44033
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.boot.convert.DurationUnit;
|
||||
import org.springframework.boot.system.JavaVersion;
|
||||
import org.springframework.boot.web.server.Compression;
|
||||
import org.springframework.boot.web.server.Cookie;
|
||||
import org.springframework.boot.web.server.Http2;
|
||||
@@ -513,6 +514,12 @@ public class ServerProperties {
|
||||
*/
|
||||
private DataSize maxHttpResponseHeaderSize = DataSize.ofKilobytes(8);
|
||||
|
||||
/**
|
||||
* Whether to use APR. If running on Java below 24, the default value is
|
||||
* 'WHEN_AVAILABLE'. On Java 24 or later, the default value is 'NEVER'.
|
||||
*/
|
||||
private UseApr useApr;
|
||||
|
||||
public DataSize getMaxHttpFormPostSize() {
|
||||
return this.maxHttpFormPostSize;
|
||||
}
|
||||
@@ -669,6 +676,18 @@ public class ServerProperties {
|
||||
this.maxHttpResponseHeaderSize = maxHttpResponseHeaderSize;
|
||||
}
|
||||
|
||||
public UseApr getUseApr() {
|
||||
if (this.useApr == null) {
|
||||
return JavaVersion.getJavaVersion().isEqualOrNewerThan(JavaVersion.TWENTY_FOUR) ? UseApr.NEVER
|
||||
: UseApr.WHEN_AVAILABLE;
|
||||
}
|
||||
return this.useApr;
|
||||
}
|
||||
|
||||
public void setUseApr(UseApr useApr) {
|
||||
this.useApr = useApr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tomcat access log properties.
|
||||
*/
|
||||
@@ -1918,4 +1937,26 @@ public class ServerProperties {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When to use APR.
|
||||
*/
|
||||
public enum UseApr {
|
||||
|
||||
/**
|
||||
* Always use APR and fail if it's not available.
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Use APR if it is available.
|
||||
*/
|
||||
WHEN_AVAILABLE,
|
||||
|
||||
/**
|
||||
* Never user APR.
|
||||
*/
|
||||
NEVER
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.web.reactive;
|
||||
|
||||
import org.apache.catalina.core.AprLifecycleListener;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties.UseApr;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link WebServerFactoryCustomizer} to apply {@link ServerProperties} to Tomcat reactive
|
||||
@@ -38,7 +43,27 @@ public class TomcatReactiveWebServerFactoryCustomizer
|
||||
|
||||
@Override
|
||||
public void customize(TomcatReactiveWebServerFactory factory) {
|
||||
factory.setDisableMBeanRegistry(!this.serverProperties.getTomcat().getMbeanregistry().isEnabled());
|
||||
Tomcat tomcatProperties = this.serverProperties.getTomcat();
|
||||
factory.setDisableMBeanRegistry(!tomcatProperties.getMbeanregistry().isEnabled());
|
||||
factory.setUseApr(getUseApr(tomcatProperties.getUseApr()));
|
||||
}
|
||||
|
||||
private boolean getUseApr(UseApr useApr) {
|
||||
return switch (useApr) {
|
||||
case ALWAYS -> {
|
||||
Assert.state(isAprAvailable(), "APR has been configured to 'ALWAYS', but it's not available");
|
||||
yield true;
|
||||
}
|
||||
case WHEN_AVAILABLE -> isAprAvailable();
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isAprAvailable() {
|
||||
// At least one instance of AprLifecycleListener has to be created for
|
||||
// isAprAvailable() to work
|
||||
new AprLifecycleListener();
|
||||
return AprLifecycleListener.isAprAvailable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.web.servlet;
|
||||
|
||||
import org.apache.catalina.core.AprLifecycleListener;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties.UseApr;
|
||||
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -56,6 +60,7 @@ public class TomcatServletWebServerFactoryCustomizer
|
||||
}
|
||||
customizeUseRelativeRedirects(factory, tomcatProperties.isUseRelativeRedirects());
|
||||
factory.setDisableMBeanRegistry(!tomcatProperties.getMbeanregistry().isEnabled());
|
||||
factory.setUseApr(getUseApr(tomcatProperties.getUseApr()));
|
||||
}
|
||||
|
||||
private void customizeRedirectContextRoot(ConfigurableTomcatWebServerFactory factory, boolean redirectContextRoot) {
|
||||
@@ -67,4 +72,22 @@ public class TomcatServletWebServerFactoryCustomizer
|
||||
factory.addContextCustomizers((context) -> context.setUseRelativeRedirects(useRelativeRedirects));
|
||||
}
|
||||
|
||||
private boolean getUseApr(UseApr useApr) {
|
||||
return switch (useApr) {
|
||||
case ALWAYS -> {
|
||||
Assert.state(isAprAvailable(), "APR has been configured to 'ALWAYS', but it's not available");
|
||||
yield true;
|
||||
}
|
||||
case WHEN_AVAILABLE -> isAprAvailable();
|
||||
case NEVER -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isAprAvailable() {
|
||||
// At least one instance of AprLifecycleListener has to be created for
|
||||
// isAprAvailable() to work
|
||||
new AprLifecycleListener();
|
||||
return AprLifecycleListener.isAprAvailable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -35,9 +35,12 @@ import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledForJreRange;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
import reactor.netty.http.HttpDecoderSpec;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Accesslog;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties.UseApr;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
|
||||
@@ -69,6 +72,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Chris Bono
|
||||
* @author Parviz Rozikov
|
||||
* @author Lasse Wulff
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
@DirtiesUrlFactories
|
||||
class ServerPropertiesTests {
|
||||
@@ -494,6 +498,18 @@ class ServerPropertiesTests {
|
||||
.isEqualTo(HttpDecoderSpec.DEFAULT_INITIAL_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledForJreRange(max = JRE.JAVA_23)
|
||||
void shouldDefaultAprToWhenAvailableUntilJava23() {
|
||||
assertThat(this.properties.getTomcat().getUseApr()).isEqualTo(UseApr.WHEN_AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledForJreRange(min = JRE.JAVA_24)
|
||||
void shouldDefaultAprToNeverOnJava24AndLater() {
|
||||
assertThat(this.properties.getTomcat().getUseApr()).isEqualTo(UseApr.NEVER);
|
||||
}
|
||||
|
||||
private Connector getDefaultConnector() {
|
||||
return new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user