Add support for configuring Jetty's backing queue

See gh-19494
pull/20193/head
cbono 5 years ago committed by Stephane Nicoll
parent a6fdbdcd80
commit 852734b129

@ -1041,6 +1041,11 @@ public class ServerProperties {
*/
private Integer minThreads = 8;
/**
* Maximum capacity of the thread pools backing queue.
*/
private Integer maxQueueCapacity;
/**
* Maximum thread idle time.
*/
@ -1106,6 +1111,14 @@ public class ServerProperties {
return this.maxThreads;
}
public void setMaxQueueCapacity(Integer maxQueueCapacity) {
this.maxQueueCapacity = maxQueueCapacity;
}
public Integer getMaxQueueCapacity() {
return this.maxQueueCapacity;
}
public void setThreadIdleTimeout(Duration threadIdleTimeout) {
this.threadIdleTimeout = threadIdleTimeout;
}

@ -0,0 +1,102 @@
/*
* 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);
}
}

@ -24,8 +24,12 @@ 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;
@ -101,6 +105,7 @@ abstract class ReactiveWebServerFactoryConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
@ConditionalOnClass({ org.eclipse.jetty.server.Server.class })
@EnableConfigurationProperties(ServerProperties.class)
static class EmbeddedJetty {
@Bean
@ -109,10 +114,17 @@ abstract class ReactiveWebServerFactoryConfiguration {
return new JettyResourceFactory();
}
@Bean
@ConditionalOnMissingBean
JettyThreadPoolFactory jettyThreadPoolFactory(ServerProperties serverProperties) {
return new JettyConstrainedQueuedThreadPoolFactory(serverProperties);
}
@Bean
JettyReactiveWebServerFactory jettyReactiveWebServerFactory(JettyResourceFactory resourceFactory,
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyThreadPoolFactory threadPoolFactory, 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,8 +32,12 @@ 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;
@ -90,12 +94,20 @@ 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
JettyServletWebServerFactory JettyServletWebServerFactory(
@ConditionalOnMissingBean
JettyThreadPoolFactory jettyThreadPoolFactory(ServerProperties serverProperties) {
return new JettyConstrainedQueuedThreadPoolFactory(serverProperties);
}
@Bean
JettyServletWebServerFactory JettyServletWebServerFactory(JettyThreadPoolFactory threadPoolFactory,
ObjectProvider<JettyServerCustomizer> serverCustomizers) {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.setThreadPool(threadPoolFactory.create());
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}

@ -75,6 +75,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Andrew McGhie
* @author HaiTao Zhang
* @author Rafiullah Hamedy
* @author Chris Bono
*/
class ServerPropertiesTests {
@ -237,6 +238,12 @@ class ServerPropertiesTests {
assertThat(this.properties.getJetty().getThreadIdleTimeout()).hasSeconds(10);
}
@Test
void testCustomizeJettyMaxQueueCapacity() {
bind("server.jetty.max-queue-capacity", "5150");
assertThat(this.properties.getJetty().getMaxQueueCapacity()).isEqualTo(5150);
}
@Test
void testCustomizeUndertowServerOption() {
bind("server.undertow.options.server.ALWAYS_SET_KEEP_ALIVE", "true");

@ -0,0 +1,108 @@
/*
* 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);
}
}

@ -22,14 +22,18 @@ 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;
@ -53,6 +57,7 @@ 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;
@ -63,6 +68,7 @@ import static org.mockito.Mockito.verify;
* @author Brian Clozel
* @author Raheela Aslam
* @author Madhura Bhave
* @author Chris Bono
*/
class ReactiveWebServerFactoryAutoConfigurationTests {
@ -242,6 +248,36 @@ 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)
@ -468,6 +504,20 @@ 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,6 +28,8 @@ 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;
@ -35,12 +37,14 @@ 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;
@ -64,6 +68,7 @@ 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;
@ -76,6 +81,7 @@ import static org.mockito.Mockito.verify;
* @author Stephane Nicoll
* @author Raheela Aslam
* @author Madhura Bhave
* @author Chris Bono
*/
class ServletWebServerFactoryAutoConfigurationTests {
@ -181,6 +187,40 @@ 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(
@ -579,6 +619,20 @@ 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 {

@ -0,0 +1,39 @@
/*
* 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();
}
Loading…
Cancel
Save