Skip to content

Commit 2bd5c29

Browse files
mhalbritterahmedhus
authored andcommitted
Problems: - Q: is there a way to only configure the TaskQueue on the existing handler?
1 parent ec9ac05 commit 2bd5c29

File tree

4 files changed

+93
-37
lines changed

4 files changed

+93
-37
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Map;
3030

3131
import io.undertow.UndertowOptions;
32+
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
3233

3334
import org.springframework.boot.context.properties.ConfigurationProperties;
3435
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
@@ -905,6 +906,16 @@ public static class Threads {
905906
*/
906907
private int minSpare = 10;
907908

909+
/**
910+
* idle time in milliseconds
911+
*/
912+
private int maxIdleTime = 60000;
913+
914+
/**
915+
* The maximum number of elements that can queue up before we reject them
916+
*/
917+
private int maxQueueSize = Integer.MAX_VALUE;
918+
908919
public int getMax() {
909920
return this.max;
910921
}
@@ -921,6 +932,21 @@ public void setMinSpare(int minSpare) {
921932
this.minSpare = minSpare;
922933
}
923934

935+
public int getMaxQueueSize() {
936+
return this.maxQueueSize;
937+
}
938+
939+
public void setMaxQueueSize(int maxQueueSize) {
940+
this.maxQueueSize = maxQueueSize;
941+
}
942+
943+
public int getMaxIdleTime() {
944+
return this.maxIdleTime;
945+
}
946+
947+
public void setMaxIdleTime(int maxIdleTime) {
948+
this.maxIdleTime = maxIdleTime;
949+
}
924950
}
925951

926952
/**

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
import java.util.function.ObjIntConsumer;
2222
import java.util.stream.Collectors;
2323

24+
import javax.management.ObjectName;
25+
2426
import org.apache.catalina.Lifecycle;
27+
import org.apache.catalina.core.StandardThreadExecutor;
2528
import org.apache.catalina.valves.AccessLogValve;
2629
import org.apache.catalina.valves.ErrorReportValve;
2730
import org.apache.catalina.valves.RemoteIpValve;
@@ -36,6 +39,7 @@
3639
import org.springframework.boot.autoconfigure.web.ServerProperties;
3740
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Accesslog;
3841
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip;
42+
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Threads;
3943
import org.springframework.boot.cloud.CloudPlatform;
4044
import org.springframework.boot.context.properties.PropertyMapper;
4145
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
@@ -90,64 +94,72 @@ public void customize(ConfigurableTomcatWebServerFactory factory) {
9094
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
9195
map.from(properties::getBasedir).to(factory::setBaseDirectory);
9296
map.from(properties::getBackgroundProcessorDelay)
93-
.as(Duration::getSeconds)
94-
.as(Long::intValue)
95-
.to(factory::setBackgroundProcessorDelay);
97+
.as(Duration::getSeconds)
98+
.as(Long::intValue)
99+
.to(factory::setBackgroundProcessorDelay);
96100
customizeRemoteIpValve(factory);
97101
ServerProperties.Tomcat.Threads threadProperties = properties.getThreads();
98-
map.from(threadProperties::getMax)
99-
.when(this::isPositive)
100-
.to((maxThreads) -> customizeMaxThreads(factory, threadProperties.getMax()));
101-
map.from(threadProperties::getMinSpare)
102-
.when(this::isPositive)
103-
.to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));
102+
configureExecutor(factory, threadProperties);
104103
map.from(this.serverProperties.getMaxHttpRequestHeaderSize())
105-
.asInt(DataSize::toBytes)
106-
.when(this::isPositive)
107-
.to((maxHttpRequestHeaderSize) -> customizeMaxHttpRequestHeaderSize(factory, maxHttpRequestHeaderSize));
104+
.asInt(DataSize::toBytes)
105+
.when(this::isPositive)
106+
.to((maxHttpRequestHeaderSize) -> customizeMaxHttpRequestHeaderSize(factory, maxHttpRequestHeaderSize));
108107
map.from(properties::getMaxHttpResponseHeaderSize)
109-
.asInt(DataSize::toBytes)
110-
.when(this::isPositive)
111-
.to((maxHttpResponseHeaderSize) -> customizeMaxHttpResponseHeaderSize(factory, maxHttpResponseHeaderSize));
108+
.asInt(DataSize::toBytes)
109+
.when(this::isPositive)
110+
.to((maxHttpResponseHeaderSize) -> customizeMaxHttpResponseHeaderSize(factory, maxHttpResponseHeaderSize));
112111
map.from(properties::getMaxSwallowSize)
113-
.asInt(DataSize::toBytes)
114-
.to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize));
112+
.asInt(DataSize::toBytes)
113+
.to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize));
115114
map.from(properties::getMaxHttpFormPostSize)
116-
.asInt(DataSize::toBytes)
117-
.when((maxHttpFormPostSize) -> maxHttpFormPostSize != 0)
118-
.to((maxHttpFormPostSize) -> customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize));
115+
.asInt(DataSize::toBytes)
116+
.when((maxHttpFormPostSize) -> maxHttpFormPostSize != 0)
117+
.to((maxHttpFormPostSize) -> customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize));
119118
map.from(properties::getAccesslog)
120-
.when(ServerProperties.Tomcat.Accesslog::isEnabled)
121-
.to((enabled) -> customizeAccessLog(factory));
119+
.when(ServerProperties.Tomcat.Accesslog::isEnabled)
120+
.to((enabled) -> customizeAccessLog(factory));
122121
map.from(properties::getUriEncoding).to(factory::setUriEncoding);
123122
map.from(properties::getConnectionTimeout)
124-
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
123+
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
125124
map.from(properties::getMaxConnections)
126-
.when(this::isPositive)
127-
.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
125+
.when(this::isPositive)
126+
.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
128127
map.from(properties::getAcceptCount)
129-
.when(this::isPositive)
130-
.to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
128+
.when(this::isPositive)
129+
.to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
131130
map.from(properties::getProcessorCache)
132-
.to((processorCache) -> customizeProcessorCache(factory, processorCache));
131+
.to((processorCache) -> customizeProcessorCache(factory, processorCache));
133132
map.from(properties::getKeepAliveTimeout)
134-
.to((keepAliveTimeout) -> customizeKeepAliveTimeout(factory, keepAliveTimeout));
133+
.to((keepAliveTimeout) -> customizeKeepAliveTimeout(factory, keepAliveTimeout));
135134
map.from(properties::getMaxKeepAliveRequests)
136-
.to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests));
135+
.to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests));
137136
map.from(properties::getRelaxedPathChars)
138-
.as(this::joinCharacters)
139-
.whenHasText()
140-
.to((relaxedChars) -> customizeRelaxedPathChars(factory, relaxedChars));
137+
.as(this::joinCharacters)
138+
.whenHasText()
139+
.to((relaxedChars) -> customizeRelaxedPathChars(factory, relaxedChars));
141140
map.from(properties::getRelaxedQueryChars)
142-
.as(this::joinCharacters)
143-
.whenHasText()
144-
.to((relaxedChars) -> customizeRelaxedQueryChars(factory, relaxedChars));
141+
.as(this::joinCharacters)
142+
.whenHasText()
143+
.to((relaxedChars) -> customizeRelaxedQueryChars(factory, relaxedChars));
145144
map.from(properties::isRejectIllegalHeader)
146-
.to((rejectIllegalHeader) -> customizeRejectIllegalHeader(factory, rejectIllegalHeader));
145+
.to((rejectIllegalHeader) -> customizeRejectIllegalHeader(factory, rejectIllegalHeader));
147146
customizeStaticResources(factory);
148147
customizeErrorReportValve(this.serverProperties.getError(), factory);
149148
}
150149

150+
private void configureExecutor(ConfigurableTomcatWebServerFactory factory, Threads threadProperties) {
151+
factory.addProtocolHandlerCustomizers((handler) -> {
152+
StandardThreadExecutor executor = new StandardThreadExecutor();
153+
executor.setMaxThreads(threadProperties.getMax());
154+
executor.setMinSpareThreads(threadProperties.getMinSpare());
155+
executor.setMaxQueueSize(threadProperties.getMaxQueueSize());
156+
if (handler instanceof AbstractProtocol<?> protocol) {
157+
executor.setNamePrefix(ObjectName.unquote(protocol.getName()) + "-exec-");
158+
}
159+
handler.setExecutor(executor);
160+
});
161+
}
162+
151163
private boolean isPositive(int value) {
152164
return value > 0;
153165
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.apache.catalina.Context;
3030
import org.apache.catalina.Engine;
31+
import org.apache.catalina.Executor;
3132
import org.apache.catalina.Host;
3233
import org.apache.catalina.LifecycleListener;
3334
import org.apache.catalina.Valve;
@@ -130,16 +131,24 @@ public WebServer getWebServer(HttpHandler httpHandler) {
130131
tomcat.getService().addConnector(connector);
131132
customizeConnector(connector);
132133
tomcat.setConnector(connector);
134+
addConnectorExecutor(connector, tomcat);
133135
tomcat.getHost().setAutoDeploy(false);
134136
configureEngine(tomcat.getEngine());
135137
for (Connector additionalConnector : this.additionalTomcatConnectors) {
136138
tomcat.getService().addConnector(additionalConnector);
139+
addConnectorExecutor(additionalConnector, tomcat);
137140
}
138141
TomcatHttpHandlerAdapter servlet = new TomcatHttpHandlerAdapter(httpHandler);
139142
prepareContext(tomcat.getHost(), servlet);
140143
return getTomcatWebServer(tomcat);
141144
}
142145

146+
private static void addConnectorExecutor(Connector connector, Tomcat tomcat) {
147+
if(connector.getProtocolHandler().getExecutor() instanceof Executor executor) {
148+
tomcat.getService().addExecutor(executor);
149+
}
150+
}
151+
143152
private void configureEngine(Engine engine) {
144153
engine.setBackgroundProcessorDelay(this.backgroundProcessorDelay);
145154
for (Valve valve : this.engineValves) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import jakarta.servlet.http.HttpServletRequest;
3939
import org.apache.catalina.Context;
4040
import org.apache.catalina.Engine;
41+
import org.apache.catalina.Executor;
4142
import org.apache.catalina.Host;
4243
import org.apache.catalina.Lifecycle;
4344
import org.apache.catalina.LifecycleEvent;
@@ -202,15 +203,23 @@ public WebServer getWebServer(ServletContextInitializer... initializers) {
202203
tomcat.getService().addConnector(connector);
203204
customizeConnector(connector);
204205
tomcat.setConnector(connector);
206+
addConnectorExecutor(connector, tomcat);
205207
tomcat.getHost().setAutoDeploy(false);
206208
configureEngine(tomcat.getEngine());
207209
for (Connector additionalConnector : this.additionalTomcatConnectors) {
208210
tomcat.getService().addConnector(additionalConnector);
211+
addConnectorExecutor(additionalConnector, tomcat);
209212
}
210213
prepareContext(tomcat.getHost(), initializers);
211214
return getTomcatWebServer(tomcat);
212215
}
213216

217+
private static void addConnectorExecutor(Connector connector, Tomcat tomcat) {
218+
if(connector.getProtocolHandler().getExecutor() instanceof Executor executor) {
219+
tomcat.getService().addExecutor(executor);
220+
}
221+
}
222+
214223
private void configureEngine(Engine engine) {
215224
engine.setBackgroundProcessorDelay(this.backgroundProcessorDelay);
216225
for (Valve valve : this.engineValves) {

0 commit comments

Comments
 (0)