Polish "Add support for configuring Jetty's backing queue"
See gh-19494
This commit is contained in:
@@ -1031,18 +1031,19 @@ public class ServerProperties {
|
||||
*/
|
||||
private Integer selectors = -1;
|
||||
|
||||
/**
|
||||
* Maximum number of threads.
|
||||
*/
|
||||
private Integer maxThreads = 200;
|
||||
|
||||
/**
|
||||
* Minimum number of threads.
|
||||
*/
|
||||
private Integer minThreads = 8;
|
||||
private int minThreads = 8;
|
||||
|
||||
/**
|
||||
* Maximum capacity of the thread pools backing queue.
|
||||
* Maximum number of threads.
|
||||
*/
|
||||
private int maxThreads = 200;
|
||||
|
||||
/**
|
||||
* Maximum capacity of the thread pool's backing queue. A default is computed
|
||||
* based on the threading configuration.
|
||||
*/
|
||||
private Integer maxQueueCapacity;
|
||||
|
||||
@@ -1095,19 +1096,19 @@ public class ServerProperties {
|
||||
this.selectors = selectors;
|
||||
}
|
||||
|
||||
public void setMinThreads(Integer minThreads) {
|
||||
public void setMinThreads(int minThreads) {
|
||||
this.minThreads = minThreads;
|
||||
}
|
||||
|
||||
public Integer getMinThreads() {
|
||||
public int getMinThreads() {
|
||||
return this.minThreads;
|
||||
}
|
||||
|
||||
public void setMaxThreads(Integer maxThreads) {
|
||||
public void setMaxThreads(int maxThreads) {
|
||||
this.maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
public Integer getMaxThreads() {
|
||||
public int getMaxThreads() {
|
||||
return this.maxThreads;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.web.embedded;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties.Jetty;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyThreadPoolFactory;
|
||||
|
||||
/**
|
||||
* A {@link JettyThreadPoolFactory} that creates a thread pool that uses a backing queue
|
||||
* with a max capacity if the {@link Jetty#maxQueueCapacity} is specified. If the max
|
||||
* capacity is not specified then the factory will return null thus allowing the standard
|
||||
* Jetty server thread pool to be used.
|
||||
*
|
||||
* @author Chris Bono
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class JettyConstrainedQueuedThreadPoolFactory implements JettyThreadPoolFactory<QueuedThreadPool> {
|
||||
|
||||
private ServerProperties serverProperties;
|
||||
|
||||
public JettyConstrainedQueuedThreadPoolFactory(ServerProperties serverProperties) {
|
||||
this.serverProperties = serverProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates a {@link QueuedThreadPool} with the following settings (if
|
||||
* {@link Jetty#maxQueueCapacity} is specified):
|
||||
* <ul>
|
||||
* <li>min threads set to {@link Jetty#minThreads} or {@code 8} if not specified.
|
||||
* <li>max threads set to {@link Jetty#maxThreads} or {@code 200} if not specified.
|
||||
* <li>idle timeout set to {@link Jetty#threadIdleTimeout} or {@code 60000} if not
|
||||
* specified.</li>
|
||||
* <li>if {@link Jetty#maxQueueCapacity} is zero its backing queue will be a
|
||||
* {@link SynchronousQueue} otherwise it will be a {@link BlockingArrayQueue} whose
|
||||
* max capacity is set to the max queue depth.
|
||||
* </ul>
|
||||
* @return thread pool as described above or {@code null} if
|
||||
* {@link Jetty#maxQueueCapacity} is not specified.
|
||||
*/
|
||||
@Override
|
||||
public QueuedThreadPool create() {
|
||||
|
||||
Integer maxQueueCapacity = this.serverProperties.getJetty().getMaxQueueCapacity();
|
||||
|
||||
// Max depth is not specified - let Jetty server use its defaults in this case
|
||||
if (maxQueueCapacity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BlockingQueue<Runnable> queue;
|
||||
if (maxQueueCapacity == 0) {
|
||||
/**
|
||||
* This queue will cause jetty to reject requests whenever there is no idle
|
||||
* thread available to handle them. If this queue is used, it is strongly
|
||||
* recommended to set _minThreads equal to _maxThreads. Jetty's
|
||||
* QueuedThreadPool class may not behave like a regular java thread pool and
|
||||
* may not add threads properly when a SynchronousQueue is used.
|
||||
*/
|
||||
queue = new SynchronousQueue<>();
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* Create a queue of fixed size. This queue will not grow. If a request
|
||||
* arrives and the queue is empty, the client will see an immediate
|
||||
* "connection reset" error.
|
||||
*/
|
||||
queue = new BlockingArrayQueue<>(maxQueueCapacity);
|
||||
}
|
||||
|
||||
Integer maxThreadCount = this.serverProperties.getJetty().getMaxThreads();
|
||||
Integer minThreadCount = this.serverProperties.getJetty().getMinThreads();
|
||||
Duration threadIdleTimeout = this.serverProperties.getJetty().getThreadIdleTimeout();
|
||||
|
||||
return new QueuedThreadPool((maxThreadCount != null) ? maxThreadCount : 200,
|
||||
(minThreadCount != null) ? minThreadCount : 8,
|
||||
(threadIdleTimeout != null) ? (int) threadIdleTimeout.toMillis() : 60000, queue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,8 @@ package org.springframework.boot.autoconfigure.web.embedded;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
@@ -30,6 +31,7 @@ import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
@@ -75,6 +77,7 @@ public class JettyWebServerFactoryCustomizer
|
||||
ServerProperties properties = this.serverProperties;
|
||||
ServerProperties.Jetty jettyProperties = properties.getJetty();
|
||||
factory.setUseForwardHeaders(getOrDeduceUseForwardHeaders());
|
||||
factory.setThreadPool(determineThreadPool(jettyProperties));
|
||||
PropertyMapper propertyMapper = PropertyMapper.get();
|
||||
propertyMapper.from(jettyProperties::getAcceptors).whenNonNull().to(factory::setAcceptors);
|
||||
propertyMapper.from(jettyProperties::getSelectors).whenNonNull().to(factory::setSelectors);
|
||||
@@ -83,12 +86,6 @@ public class JettyWebServerFactoryCustomizer
|
||||
.addServerCustomizers(new MaxHttpHeaderSizeCustomizer(maxHttpHeaderSize)));
|
||||
propertyMapper.from(jettyProperties::getMaxHttpFormPostSize).asInt(DataSize::toBytes).when(this::isPositive)
|
||||
.to((maxHttpFormPostSize) -> customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize));
|
||||
propertyMapper.from(jettyProperties::getMaxThreads).when(this::isPositive)
|
||||
.to((maxThreads) -> customizeThreadPool(factory, (threadPool) -> threadPool.setMaxThreads(maxThreads)));
|
||||
propertyMapper.from(jettyProperties::getMinThreads).when(this::isPositive)
|
||||
.to((minThreads) -> customizeThreadPool(factory, (threadPool) -> threadPool.setMinThreads(minThreads)));
|
||||
propertyMapper.from(jettyProperties::getThreadIdleTimeout).whenNonNull().asInt(Duration::toMillis).to(
|
||||
(idleTimeout) -> customizeThreadPool(factory, (threadPool) -> threadPool.setIdleTimeout(idleTimeout)));
|
||||
propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
|
||||
.to((connectionTimeout) -> customizeIdleTimeout(factory, connectionTimeout));
|
||||
propertyMapper.from(jettyProperties::getConnectionIdleTimeout).whenNonNull()
|
||||
@@ -144,13 +141,25 @@ public class JettyWebServerFactoryCustomizer
|
||||
});
|
||||
}
|
||||
|
||||
private void customizeThreadPool(ConfigurableJettyWebServerFactory factory, Consumer<QueuedThreadPool> customizer) {
|
||||
factory.addServerCustomizers((connector) -> {
|
||||
ThreadPool threadPool = connector.getThreadPool();
|
||||
if (threadPool instanceof QueuedThreadPool) {
|
||||
customizer.accept((QueuedThreadPool) threadPool);
|
||||
}
|
||||
});
|
||||
private ThreadPool determineThreadPool(ServerProperties.Jetty properties) {
|
||||
BlockingQueue<Runnable> queue = determineBlockingQueue(properties.getMaxQueueCapacity());
|
||||
int maxThreadCount = (properties.getMaxThreads() > 0) ? properties.getMaxThreads() : 200;
|
||||
int minThreadCount = (properties.getMinThreads() > 0) ? properties.getMinThreads() : 8;
|
||||
int threadIdleTimeout = (properties.getThreadIdleTimeout() != null)
|
||||
? (int) properties.getThreadIdleTimeout().toMillis() : 60000;
|
||||
return new QueuedThreadPool(maxThreadCount, minThreadCount, threadIdleTimeout, queue);
|
||||
}
|
||||
|
||||
private BlockingQueue<Runnable> determineBlockingQueue(Integer maxQueueCapacity) {
|
||||
if (maxQueueCapacity == null) {
|
||||
return null;
|
||||
}
|
||||
if (maxQueueCapacity == 0) {
|
||||
return new SynchronousQueue<>();
|
||||
}
|
||||
else {
|
||||
return new BlockingArrayQueue<>(maxQueueCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
private void customizeAccessLog(ConfigurableJettyWebServerFactory factory,
|
||||
|
||||
@@ -24,12 +24,8 @@ import reactor.netty.http.server.HttpServer;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.embedded.JettyConstrainedQueuedThreadPoolFactory;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyThreadPoolFactory;
|
||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.netty.NettyRouteProvider;
|
||||
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
|
||||
@@ -105,7 +101,6 @@ abstract class ReactiveWebServerFactoryConfiguration {
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
|
||||
@ConditionalOnClass({ org.eclipse.jetty.server.Server.class })
|
||||
@EnableConfigurationProperties(ServerProperties.class)
|
||||
static class EmbeddedJetty {
|
||||
|
||||
@Bean
|
||||
@@ -114,17 +109,10 @@ abstract class ReactiveWebServerFactoryConfiguration {
|
||||
return new JettyResourceFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
JettyThreadPoolFactory jettyThreadPoolFactory(ServerProperties serverProperties) {
|
||||
return new JettyConstrainedQueuedThreadPoolFactory(serverProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
JettyReactiveWebServerFactory jettyReactiveWebServerFactory(JettyResourceFactory resourceFactory,
|
||||
JettyThreadPoolFactory threadPoolFactory, ObjectProvider<JettyServerCustomizer> serverCustomizers) {
|
||||
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
|
||||
JettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory();
|
||||
serverFactory.setThreadPool(threadPoolFactory.create());
|
||||
serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
|
||||
serverFactory.setResourceFactory(resourceFactory);
|
||||
return serverFactory;
|
||||
|
||||
@@ -32,12 +32,8 @@ import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.embedded.JettyConstrainedQueuedThreadPoolFactory;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyThreadPoolFactory;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
|
||||
@@ -94,20 +90,12 @@ class ServletWebServerFactoryConfiguration {
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
|
||||
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
|
||||
@EnableConfigurationProperties(ServerProperties.class)
|
||||
static class EmbeddedJetty {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
JettyThreadPoolFactory jettyThreadPoolFactory(ServerProperties serverProperties) {
|
||||
return new JettyConstrainedQueuedThreadPoolFactory(serverProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
JettyServletWebServerFactory JettyServletWebServerFactory(JettyThreadPoolFactory threadPoolFactory,
|
||||
JettyServletWebServerFactory JettyServletWebServerFactory(
|
||||
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
|
||||
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
|
||||
factory.setThreadPool(threadPoolFactory.create());
|
||||
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
|
||||
return factory;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Andrew McGhie
|
||||
* @author HaiTao Zhang
|
||||
* @author Rafiullah Hamedy
|
||||
* @author Chris Bono
|
||||
*/
|
||||
class ServerPropertiesTests {
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.web.embedded;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.test.context.support.TestPropertySourceUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link JettyConstrainedQueuedThreadPoolFactory}.
|
||||
*
|
||||
* @author Chris Bono
|
||||
*/
|
||||
class JettyConstrainedQueuedThreadPoolFactoryTest {
|
||||
|
||||
private MockEnvironment environment;
|
||||
|
||||
private ServerProperties serverProperties;
|
||||
|
||||
private JettyConstrainedQueuedThreadPoolFactory factory;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.environment = new MockEnvironment();
|
||||
this.serverProperties = new ServerProperties();
|
||||
ConfigurationPropertySources.attach(this.environment);
|
||||
this.factory = new JettyConstrainedQueuedThreadPoolFactory(this.serverProperties);
|
||||
}
|
||||
|
||||
@Test
|
||||
void factoryReturnsNullWhenMaxCapacityNotSpecified() {
|
||||
bind("server.jetty.max-queue-capacity=");
|
||||
assertThat(this.factory.create()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void factoryReturnsSynchronousQueueWhenMaxCapacityIsZero() {
|
||||
bind("server.jetty.max-queue-capacity=0");
|
||||
QueuedThreadPool queuedThreadPool = this.factory.create();
|
||||
assertThat(getQueue(queuedThreadPool, SynchronousQueue.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void factoryReturnsBlockingArrayQueueWithDefaultsWhenOnlyMaxCapacityIsSet() {
|
||||
bind("server.jetty.max-queue-capacity=5150");
|
||||
QueuedThreadPool queuedThreadPool = this.factory.create();
|
||||
assertThat(queuedThreadPool.getMinThreads()).isEqualTo(8);
|
||||
assertThat(queuedThreadPool.getMaxThreads()).isEqualTo(200);
|
||||
assertThat(queuedThreadPool.getIdleTimeout()).isEqualTo(60000);
|
||||
assertThat(getQueue(queuedThreadPool, BlockingArrayQueue.class).getMaxCapacity()).isEqualTo(5150);
|
||||
}
|
||||
|
||||
@Test
|
||||
void factoryReturnsBlockingArrayQueueWithCustomValues() {
|
||||
bind("server.jetty.max-queue-capacity=5150", "server.jetty.min-threads=200", "server.jetty.max-threads=1000",
|
||||
"server.jetty.thread-idle-timeout=10000");
|
||||
QueuedThreadPool queuedThreadPool = this.factory.create();
|
||||
assertThat(queuedThreadPool.getMinThreads()).isEqualTo(200);
|
||||
assertThat(queuedThreadPool.getMaxThreads()).isEqualTo(1000);
|
||||
assertThat(queuedThreadPool.getIdleTimeout()).isEqualTo(10000);
|
||||
assertThat(getQueue(queuedThreadPool, BlockingArrayQueue.class).getMaxCapacity()).isEqualTo(5150);
|
||||
}
|
||||
|
||||
private void bind(String... inlinedProperties) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties);
|
||||
new Binder(ConfigurationPropertySources.get(this.environment)).bind("server",
|
||||
Bindable.ofInstance(this.serverProperties));
|
||||
}
|
||||
|
||||
static <T extends BlockingQueue<Runnable>> T getQueue(QueuedThreadPool queuedThreadPool,
|
||||
Class<T> expectedQueueClass) {
|
||||
Method getQueue = ReflectionUtils.findMethod(QueuedThreadPool.class, "getQueue");
|
||||
ReflectionUtils.makeAccessible(getQueue);
|
||||
Object obj = ReflectionUtils.invokeMethod(getQueue, queuedThreadPool);
|
||||
assertThat(obj).isInstanceOf(expectedQueueClass);
|
||||
return expectedQueueClass.cast(obj);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,9 +18,12 @@ package org.springframework.boot.autoconfigure.web.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
@@ -30,11 +33,15 @@ import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConfiguration.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.RequestLogWriter;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties.Jetty;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||
@@ -43,6 +50,7 @@ import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.test.context.support.TestPropertySourceUtils;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -135,7 +143,26 @@ class JettyWebServerFactoryCustomizerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void maxThreadsCanBeCustomized() {
|
||||
void threadPoolMatchesJettyDefaults() {
|
||||
ThreadPool defaultThreadPool = new Server(0).getThreadPool();
|
||||
ThreadPool configuredThreadPool = customizeAndGetServer().getServer().getThreadPool();
|
||||
assertThat(defaultThreadPool).isInstanceOf(QueuedThreadPool.class);
|
||||
assertThat(configuredThreadPool).isInstanceOf(QueuedThreadPool.class);
|
||||
QueuedThreadPool defaultQueuedThreadPool = (QueuedThreadPool) defaultThreadPool;
|
||||
QueuedThreadPool configuredQueuedThreadPool = (QueuedThreadPool) configuredThreadPool;
|
||||
assertThat(configuredQueuedThreadPool.getMinThreads()).isEqualTo(defaultQueuedThreadPool.getMinThreads());
|
||||
assertThat(configuredQueuedThreadPool.getMaxThreads()).isEqualTo(defaultQueuedThreadPool.getMaxThreads());
|
||||
assertThat(configuredQueuedThreadPool.getIdleTimeout()).isEqualTo(defaultQueuedThreadPool.getIdleTimeout());
|
||||
BlockingQueue<?> defaultQueue = getQueue(defaultThreadPool);
|
||||
BlockingQueue<?> configuredQueue = getQueue(configuredThreadPool);
|
||||
assertThat(defaultQueue).isInstanceOf(BlockingArrayQueue.class);
|
||||
assertThat(configuredQueue).isInstanceOf(BlockingArrayQueue.class);
|
||||
assertThat(((BlockingArrayQueue<?>) defaultQueue).getMaxCapacity())
|
||||
.isEqualTo(((BlockingArrayQueue<?>) configuredQueue).getMaxCapacity());
|
||||
}
|
||||
|
||||
@Test
|
||||
void threadPoolMaxThreadsCanBeCustomized() {
|
||||
bind("server.jetty.max-threads=100");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
QueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();
|
||||
@@ -143,7 +170,7 @@ class JettyWebServerFactoryCustomizerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void minThreadsCanBeCustomized() {
|
||||
void threadPoolMinThreadsCanBeCustomized() {
|
||||
bind("server.jetty.min-threads=100");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
QueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();
|
||||
@@ -151,13 +178,65 @@ class JettyWebServerFactoryCustomizerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void threadIdleTimeoutCanBeCustomized() {
|
||||
void threadPoolIdleTimeoutCanBeCustomized() {
|
||||
bind("server.jetty.thread-idle-timeout=100s");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
QueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();
|
||||
assertThat(threadPool.getIdleTimeout()).isEqualTo(100000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void threadPoolWithMaxQueueCapacityEqualToZeroCreateSynchronousQueue() {
|
||||
bind("server.jetty.max-queue-capacity=0");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
ThreadPool threadPool = server.getServer().getThreadPool();
|
||||
BlockingQueue<?> queue = getQueue(threadPool);
|
||||
assertThat(queue).isInstanceOf(SynchronousQueue.class);
|
||||
assertDefaultThreadPoolSettings(threadPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
void threadPoolWithMaxQueueCapacityEqualToZeroCustomizesThreadPool() {
|
||||
bind("server.jetty.max-queue-capacity=0", "server.jetty.min-threads=100", "server.jetty.max-threads=100",
|
||||
"server.jetty.thread-idle-timeout=6s");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
QueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();
|
||||
assertThat(threadPool.getMinThreads()).isEqualTo(100);
|
||||
assertThat(threadPool.getMaxThreads()).isEqualTo(100);
|
||||
assertThat(threadPool.getIdleTimeout()).isEqualTo(Duration.ofSeconds(6).toMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
void threadPoolWithMaxQueueCapacityPositiveCreateBlockingArrayQueue() {
|
||||
bind("server.jetty.max-queue-capacity=1234");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
ThreadPool threadPool = server.getServer().getThreadPool();
|
||||
BlockingQueue<?> queue = getQueue(threadPool);
|
||||
assertThat(queue).isInstanceOf(BlockingArrayQueue.class);
|
||||
assertThat(((BlockingArrayQueue<?>) queue).getMaxCapacity()).isEqualTo(1234);
|
||||
assertDefaultThreadPoolSettings(threadPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
void threadPoolWithMaxQueueCapacityPositiveCustomizesThreadPool() {
|
||||
bind("server.jetty.max-queue-capacity=1234", "server.jetty.min-threads=10", "server.jetty.max-threads=150",
|
||||
"server.jetty.thread-idle-timeout=3s");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
QueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();
|
||||
assertThat(threadPool.getMinThreads()).isEqualTo(10);
|
||||
assertThat(threadPool.getMaxThreads()).isEqualTo(150);
|
||||
assertThat(threadPool.getIdleTimeout()).isEqualTo(Duration.ofSeconds(3).toMillis());
|
||||
}
|
||||
|
||||
private void assertDefaultThreadPoolSettings(ThreadPool threadPool) {
|
||||
assertThat(threadPool).isInstanceOf(QueuedThreadPool.class);
|
||||
QueuedThreadPool queuedThreadPool = (QueuedThreadPool) threadPool;
|
||||
Jetty defaultProperties = new Jetty();
|
||||
assertThat(queuedThreadPool.getMinThreads()).isEqualTo(defaultProperties.getMinThreads());
|
||||
assertThat(queuedThreadPool.getMaxThreads()).isEqualTo(defaultProperties.getMaxThreads());
|
||||
assertThat(queuedThreadPool.getIdleTimeout()).isEqualTo(defaultProperties.getThreadIdleTimeout().toMillis());
|
||||
}
|
||||
|
||||
private CustomRequestLog getRequestLog(JettyWebServer server) {
|
||||
RequestLog requestLog = server.getServer().getRequestLog();
|
||||
assertThat(requestLog).isInstanceOf(CustomRequestLog.class);
|
||||
@@ -236,6 +315,10 @@ class JettyWebServerFactoryCustomizerTests {
|
||||
return requestHeaderSizes;
|
||||
}
|
||||
|
||||
private BlockingQueue<?> getQueue(ThreadPool threadPool) {
|
||||
return ReflectionTestUtils.invokeMethod(threadPool, "getQueue");
|
||||
}
|
||||
|
||||
private void bind(String... inlinedProperties) {
|
||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties);
|
||||
new Binder(ConfigurationPropertySources.get(this.environment)).bind("server",
|
||||
|
||||
@@ -22,18 +22,14 @@ import org.apache.catalina.Context;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.netty.http.server.HttpServer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.embedded.JettyConstrainedQueuedThreadPoolFactory;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyThreadPoolFactory;
|
||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
|
||||
@@ -57,7 +53,6 @@ import org.springframework.web.server.adapter.ForwardedHeaderTransformer;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.when;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -68,7 +63,6 @@ import static org.mockito.Mockito.verify;
|
||||
* @author Brian Clozel
|
||||
* @author Raheela Aslam
|
||||
* @author Madhura Bhave
|
||||
* @author Chris Bono
|
||||
*/
|
||||
class ReactiveWebServerFactoryAutoConfigurationTests {
|
||||
|
||||
@@ -248,36 +242,6 @@ class ReactiveWebServerFactoryAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jettyDefaultThreadPoolFactoryUsedToCreateThreadPoolOnWebServerFactory() {
|
||||
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
|
||||
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class))
|
||||
.withUserConfiguration(DoubleRegistrationJettyServerCustomizerConfiguration.class,
|
||||
HttpHandlerConfiguration.class)
|
||||
.withPropertyValues("server.port=0", "server.jetty.max-queue-capacity:5150").run((context) -> {
|
||||
assertThat(context.getBean(JettyThreadPoolFactory.class))
|
||||
.isInstanceOf(JettyConstrainedQueuedThreadPoolFactory.class);
|
||||
JettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);
|
||||
assertThat(factory.getThreadPool()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jettyCustomThreadPoolFactoryUsedToCreateThreadPoolOnWebServerFactory() {
|
||||
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class))
|
||||
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class))
|
||||
.withUserConfiguration(JettyCustomThreadPoolFactoryConfiguration.class, HttpHandlerConfiguration.class)
|
||||
.withPropertyValues("server.port=0").run((context) -> {
|
||||
JettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);
|
||||
JettyThreadPoolFactory threadPoolFactory = context.getBean("jettyCustomThreadPoolFactory",
|
||||
JettyThreadPoolFactory.class);
|
||||
verify(threadPoolFactory, times(1)).create();
|
||||
assertThat(factory.getThreadPool()).isSameAs(JettyCustomThreadPoolFactoryConfiguration.threadPool);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void undertowBuilderCustomizerBeanIsAddedToFactory() {
|
||||
new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebApplicationContext::new)
|
||||
@@ -504,20 +468,6 @@ class ReactiveWebServerFactoryAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JettyCustomThreadPoolFactoryConfiguration {
|
||||
|
||||
static ThreadPool threadPool = new QueuedThreadPool();
|
||||
|
||||
@Bean
|
||||
JettyThreadPoolFactory jettyCustomThreadPoolFactory() {
|
||||
JettyThreadPoolFactory threadPoolFactory = mock(JettyThreadPoolFactory.class);
|
||||
when(threadPoolFactory.create()).thenReturn(threadPool);
|
||||
return threadPoolFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class UndertowBuilderCustomizerConfiguration {
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ import org.apache.catalina.Context;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.netty.http.server.HttpServer;
|
||||
|
||||
@@ -37,14 +35,12 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.web.embedded.JettyConstrainedQueuedThreadPoolFactory;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyThreadPoolFactory;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
|
||||
@@ -68,7 +64,6 @@ import org.springframework.web.servlet.FrameworkServlet;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.when;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -81,7 +76,6 @@ import static org.mockito.Mockito.verify;
|
||||
* @author Stephane Nicoll
|
||||
* @author Raheela Aslam
|
||||
* @author Madhura Bhave
|
||||
* @author Chris Bono
|
||||
*/
|
||||
class ServletWebServerFactoryAutoConfigurationTests {
|
||||
|
||||
@@ -187,40 +181,6 @@ class ServletWebServerFactoryAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jettyDefaultThreadPoolFactoryUsedToCreateThreadPoolOnWebServerFactory() {
|
||||
WebApplicationContextRunner runner = new WebApplicationContextRunner(
|
||||
AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class))
|
||||
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class))
|
||||
.withPropertyValues("server.port:0", "server.jetty.max-queue-capacity:5150");
|
||||
runner.run((context) -> {
|
||||
assertThat(context.getBean(JettyThreadPoolFactory.class))
|
||||
.isInstanceOf(JettyConstrainedQueuedThreadPoolFactory.class);
|
||||
JettyServletWebServerFactory factory = context.getBean(JettyServletWebServerFactory.class);
|
||||
assertThat(factory.getThreadPool()).isNotNull(); // its null by default so
|
||||
// this verifies the
|
||||
// factory was used
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void jettyCustomThreadPoolFactoryUsedToCreateThreadPoolOnWebServerFactory() {
|
||||
WebApplicationContextRunner runner = new WebApplicationContextRunner(
|
||||
AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withClassLoader(new FilteredClassLoader(Tomcat.class, HttpServer.class))
|
||||
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class))
|
||||
.withUserConfiguration(JettyCustomThreadPoolFactoryConfiguration.class)
|
||||
.withPropertyValues("server.port:0");
|
||||
runner.run((context) -> {
|
||||
JettyServletWebServerFactory factory = context.getBean(JettyServletWebServerFactory.class);
|
||||
JettyThreadPoolFactory threadPoolFactory = context.getBean("jettyCustomThreadPoolFactory",
|
||||
JettyThreadPoolFactory.class);
|
||||
verify(threadPoolFactory, times(1)).create();
|
||||
assertThat(factory.getThreadPool()).isSameAs(JettyCustomThreadPoolFactoryConfiguration.threadPool);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void undertowDeploymentInfoCustomizerBeanIsAddedToFactory() {
|
||||
WebApplicationContextRunner runner = new WebApplicationContextRunner(
|
||||
@@ -619,20 +579,6 @@ class ServletWebServerFactoryAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JettyCustomThreadPoolFactoryConfiguration {
|
||||
|
||||
static ThreadPool threadPool = new QueuedThreadPool();
|
||||
|
||||
@Bean
|
||||
JettyThreadPoolFactory jettyCustomThreadPoolFactory() {
|
||||
JettyThreadPoolFactory threadPoolFactory = mock(JettyThreadPoolFactory.class);
|
||||
when(threadPoolFactory.create()).thenReturn(threadPool);
|
||||
return threadPoolFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class UndertowBuilderCustomizerConfiguration {
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.web.embedded.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
|
||||
|
||||
@@ -36,6 +37,13 @@ public interface ConfigurableJettyWebServerFactory extends ConfigurableWebServer
|
||||
*/
|
||||
void setAcceptors(int acceptors);
|
||||
|
||||
/**
|
||||
* Set the {@link ThreadPool} that should be used by the {@link Server}. If set to
|
||||
* {@code null} (default), the {@link Server} creates a {@link ThreadPool} implicitly.
|
||||
* @param threadPool the ThreadPool to be used
|
||||
*/
|
||||
void setThreadPool(ThreadPool threadPool);
|
||||
|
||||
/**
|
||||
* Set the number of selector threads to use.
|
||||
* @param selectors the number of selector threads to use
|
||||
|
||||
@@ -139,11 +139,7 @@ public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
|
||||
return this.threadPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Jetty {@link ThreadPool} that should be used by the {@link Server}. If set to
|
||||
* {@code null} (default), the {@link Server} creates a {@link ThreadPool} implicitly.
|
||||
* @param threadPool a Jetty ThreadPool to be used
|
||||
*/
|
||||
@Override
|
||||
public void setThreadPool(ThreadPool threadPool) {
|
||||
this.threadPool = threadPool;
|
||||
}
|
||||
|
||||
@@ -484,11 +484,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
|
||||
return this.threadPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Jetty {@link ThreadPool} that should be used by the {@link Server}. If set to
|
||||
* {@code null} (default), the {@link Server} creates a {@link ThreadPool} implicitly.
|
||||
* @param threadPool a Jetty ThreadPool to be used
|
||||
*/
|
||||
@Override
|
||||
public void setThreadPool(ThreadPool threadPool) {
|
||||
this.threadPool = threadPool;
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.web.embedded.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* Factory to create a thread pool for use by a Jetty {@link Server}.
|
||||
*
|
||||
* @author Chris Bono
|
||||
* @since 2.3.0
|
||||
* @param <T> type of ThreadPool that the factory returns
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface JettyThreadPoolFactory<T extends ThreadPool> {
|
||||
|
||||
/**
|
||||
* Creates a thread pool.
|
||||
* @return a Jetty thread pool or null to use the default Jetty {@link Server} thread
|
||||
* pool.
|
||||
*/
|
||||
T create();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user