Merge branch '3.4.x'

This sets the default value of 'server.tomcat.use-apr' to 'NEVER'.

Closes gh-44705
This commit is contained in:
Moritz Halbritter
2025-03-13 08:58:18 +01:00
10 changed files with 160 additions and 42 deletions

View File

@@ -519,6 +519,11 @@ public class ServerProperties {
*/
private int maxParameterCount = 10000;
/**
* Whether to use APR.
*/
private UseApr useApr = UseApr.NEVER;
public Accesslog getAccesslog() {
return this.accesslog;
}
@@ -683,6 +688,14 @@ public class ServerProperties {
this.maxParameterCount = maxParameterCount;
}
public UseApr getUseApr() {
return this.useApr;
}
public void setUseApr(UseApr useApr) {
this.useApr = useApr;
}
/**
* Tomcat access log properties.
*/
@@ -1932,4 +1945,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
}
}

View File

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

View File

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

View File

@@ -38,6 +38,7 @@ import org.junit.jupiter.api.Test;
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 +70,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Bono
* @author Parviz Rozikov
* @author Lasse Wulff
* @author Moritz Halbritter
*/
@DirtiesUrlFactories
class ServerPropertiesTests {
@@ -506,6 +508,11 @@ class ServerPropertiesTests {
.isEqualTo(HttpDecoderSpec.DEFAULT_INITIAL_BUFFER_SIZE);
}
@Test
void shouldDefaultAprToNever() {
assertThat(this.properties.getTomcat().getUseApr()).isEqualTo(UseApr.NEVER);
}
private Connector getDefaultConnector() {
return new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
}