This factory implements {@link InitializingBean} and {@link DisposableBean} + * and is expected typically to be declared as a Spring-managed bean. + * + * @author Sebastien Deleuze + * @since 5.1 + */ +public class JettyResourceFactory implements InitializingBean, DisposableBean { + + @Nullable + private Executor executor; + + @Nullable + private ByteBufferPool byteBufferPool; + + @Nullable + private Scheduler scheduler; + + private String threadPrefix = "jetty-http"; + + + /** + * Configure the {@link Executor} to use. + *
By default, initialized with a {@link QueuedThreadPool}. + * @param executor the executor to use + */ + public void setExecutor(@Nullable Executor executor) { + this.executor = executor; + } + + /** + * Configure the {@link ByteBufferPool} to use. + *
By default, initialized with a {@link MappedByteBufferPool}. + * @param byteBufferPool the {@link ByteBuffer} pool to use + */ + public void setByteBufferPool(@Nullable ByteBufferPool byteBufferPool) { + this.byteBufferPool = byteBufferPool; + } + + /** + * Configure the {@link Scheduler} to use. + *
By default, initialized with a {@link ScheduledExecutorScheduler}. + * @param scheduler the {@link Scheduler} to use + */ + public void setScheduler(@Nullable Scheduler scheduler) { + this.scheduler = scheduler; + } + + /** + * Configure the thread prefix to initialize {@link QueuedThreadPool} executor with. This + * is used only when a {@link Executor} instance isn't + * {@link #setExecutor(Executor) provided}. + *
By default set to "jetty-http".
+ * @param threadPrefix the thread prefix to use
+ */
+ public void setThreadPrefix(String threadPrefix) {
+ Assert.notNull(threadPrefix, "Thread prefix is required");
+ this.threadPrefix = threadPrefix;
+ }
+
+ /**
+ * Return the configured {@link Executor}.
+ */
+ @Nullable
+ public Executor getExecutor() {
+ return this.executor;
+ }
+
+ /**
+ * Return the configured {@link ByteBufferPool}.
+ */
+ @Nullable
+ public ByteBufferPool getByteBufferPool() {
+ return this.byteBufferPool;
+ }
+
+ /**
+ * Return the configured {@link Scheduler}.
+ */
+ @Nullable
+ public Scheduler getScheduler() {
+ return this.scheduler;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ String name = this.threadPrefix + "@" + Integer.toHexString(hashCode());
+ if (this.executor == null) {
+ QueuedThreadPool threadPool = new QueuedThreadPool();
+ threadPool.setName(name);
+ threadPool.start();
+ this.executor = threadPool;
+ }
+ if (this.byteBufferPool == null) {
+ this.byteBufferPool = new MappedByteBufferPool(2048,
+ this.executor instanceof ThreadPool.SizedThreadPool
+ ? ((ThreadPool.SizedThreadPool) executor).getMaxThreads() / 2
+ : ProcessorUtils.availableProcessors() * 2);
+ }
+ if (this.scheduler == null) {
+ Scheduler scheduler = new ScheduledExecutorScheduler(name + "-scheduler", false);
+ scheduler.start();
+ this.scheduler = scheduler;
+ }
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ if (this.executor instanceof ContainerLifeCycle) {
+ ((ContainerLifeCycle)this.executor).stop();
+ }
+ if (this.scheduler != null) {
+ this.scheduler.stop();
+ }
+ }
+
+}
diff --git a/src/docs/asciidoc/web/webflux-webclient.adoc b/src/docs/asciidoc/web/webflux-webclient.adoc
index cd532b4338..46ed9dc9a0 100644
--- a/src/docs/asciidoc/web/webflux-webclient.adoc
+++ b/src/docs/asciidoc/web/webflux-webclient.adoc
@@ -138,6 +138,54 @@ instances use shared resources:
<3> Plug the connector into the `WebClient.Builder`.
+[[webflux-client-builder-jetty]]
+=== Jetty
+
+To customize Jetty `HttpClient` settings:
+
+[source,java,intent=0]
+[subs="verbatim,quotes"]
+----
+ HttpClient httpClient = new HttpClient();
+ httpClient.setCookieStore(...);
+ ClientHttpConnector connector = new JettyClientHttpConnector(httpClient);
+
+ WebClient webClient = WebClient.builder().clientConnector(connector).build();
+----
+
+By default `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`)
+which remain active until the process exits or `stop()` is called.
+
+You can share resources between multiple intances of Jetty client (and server) and ensure the
+resources are shut down when the Spring `ApplicationContext` is closed by declaring a
+Spring-managed bean of type `JettyResourceFactory`:
+
+[source,java,intent=0]
+[subs="verbatim,quotes"]
+----
+ @Bean
+ public JettyResourceFactory resourceFactory() {
+ return new JettyResourceFactory();
+ }
+
+ @Bean
+ public WebClient webClient() {
+
+ Consumer