|
21 | 21 | import java.util.function.ObjIntConsumer;
|
22 | 22 | import java.util.stream.Collectors;
|
23 | 23 |
|
| 24 | +import javax.management.ObjectName; |
| 25 | + |
24 | 26 | import org.apache.catalina.Lifecycle;
|
| 27 | +import org.apache.catalina.core.StandardThreadExecutor; |
25 | 28 | import org.apache.catalina.valves.AccessLogValve;
|
26 | 29 | import org.apache.catalina.valves.ErrorReportValve;
|
27 | 30 | import org.apache.catalina.valves.RemoteIpValve;
|
|
36 | 39 | import org.springframework.boot.autoconfigure.web.ServerProperties;
|
37 | 40 | import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Accesslog;
|
38 | 41 | import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip;
|
| 42 | +import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Threads; |
39 | 43 | import org.springframework.boot.cloud.CloudPlatform;
|
40 | 44 | import org.springframework.boot.context.properties.PropertyMapper;
|
41 | 45 | import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
|
@@ -90,64 +94,72 @@ public void customize(ConfigurableTomcatWebServerFactory factory) {
|
90 | 94 | PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
91 | 95 | map.from(properties::getBasedir).to(factory::setBaseDirectory);
|
92 | 96 | 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); |
96 | 100 | customizeRemoteIpValve(factory);
|
97 | 101 | 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); |
104 | 103 | 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)); |
108 | 107 | 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)); |
112 | 111 | map.from(properties::getMaxSwallowSize)
|
113 |
| - .asInt(DataSize::toBytes) |
114 |
| - .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); |
| 112 | + .asInt(DataSize::toBytes) |
| 113 | + .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); |
115 | 114 | 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)); |
119 | 118 | 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)); |
122 | 121 | map.from(properties::getUriEncoding).to(factory::setUriEncoding);
|
123 | 122 | map.from(properties::getConnectionTimeout)
|
124 |
| - .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout)); |
| 123 | + .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout)); |
125 | 124 | map.from(properties::getMaxConnections)
|
126 |
| - .when(this::isPositive) |
127 |
| - .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); |
| 125 | + .when(this::isPositive) |
| 126 | + .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); |
128 | 127 | map.from(properties::getAcceptCount)
|
129 |
| - .when(this::isPositive) |
130 |
| - .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); |
| 128 | + .when(this::isPositive) |
| 129 | + .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); |
131 | 130 | map.from(properties::getProcessorCache)
|
132 |
| - .to((processorCache) -> customizeProcessorCache(factory, processorCache)); |
| 131 | + .to((processorCache) -> customizeProcessorCache(factory, processorCache)); |
133 | 132 | map.from(properties::getKeepAliveTimeout)
|
134 |
| - .to((keepAliveTimeout) -> customizeKeepAliveTimeout(factory, keepAliveTimeout)); |
| 133 | + .to((keepAliveTimeout) -> customizeKeepAliveTimeout(factory, keepAliveTimeout)); |
135 | 134 | map.from(properties::getMaxKeepAliveRequests)
|
136 |
| - .to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests)); |
| 135 | + .to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests)); |
137 | 136 | 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)); |
141 | 140 | 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)); |
145 | 144 | map.from(properties::isRejectIllegalHeader)
|
146 |
| - .to((rejectIllegalHeader) -> customizeRejectIllegalHeader(factory, rejectIllegalHeader)); |
| 145 | + .to((rejectIllegalHeader) -> customizeRejectIllegalHeader(factory, rejectIllegalHeader)); |
147 | 146 | customizeStaticResources(factory);
|
148 | 147 | customizeErrorReportValve(this.serverProperties.getError(), factory);
|
149 | 148 | }
|
150 | 149 |
|
| 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 | + |
151 | 163 | private boolean isPositive(int value) {
|
152 | 164 | return value > 0;
|
153 | 165 | }
|
|
0 commit comments