diff --git a/spring-web/src/main/java/org/springframework/http/client/ReactorResourceFactory.java b/spring-web/src/main/java/org/springframework/http/client/ReactorResourceFactory.java index faed920cf66..3d1a0982acb 100644 --- a/spring-web/src/main/java/org/springframework/http/client/ReactorResourceFactory.java +++ b/spring-web/src/main/java/org/springframework/http/client/ReactorResourceFactory.java @@ -61,12 +61,12 @@ public class ReactorResourceFactory private Supplier connectionProviderSupplier = () -> ConnectionProvider.create("webflux", 500); @Nullable - private ConnectionProvider connectionProvider; + private volatile ConnectionProvider connectionProvider; private Supplier loopResourcesSupplier = () -> LoopResources.create("webflux-http"); @Nullable - private LoopResources loopResources; + private volatile LoopResources loopResources; private boolean manageConnectionProvider = false; @@ -141,16 +141,22 @@ public class ReactorResourceFactory /** * Return the configured {@link ConnectionProvider}. + *

Lazily tries to start the resources on demand if not initialized yet. + * @see #start() */ public ConnectionProvider getConnectionProvider() { - Assert.state(this.connectionProvider != null, "ConnectionProvider not initialized yet"); - return this.connectionProvider; + if (this.connectionProvider == null) { + start(); + } + ConnectionProvider connectionProvider = this.connectionProvider; + Assert.state(connectionProvider != null, "ConnectionProvider not initialized"); + return connectionProvider; } /** * Use this when you don't want to participate in global resources and * you want to customize the creation of the managed {@code LoopResources}. - *

By default, {@code LoopResources.create("reactor-http")} is used. + *

By default, {@code LoopResources.create("webflux-http")} is used. *

Note that this option is ignored if {@code userGlobalResources=false} or * {@link #setLoopResources(LoopResources)} is set. * @param supplier the supplier to use @@ -170,10 +176,16 @@ public class ReactorResourceFactory /** * Return the configured {@link LoopResources}. + *

Lazily tries to start the resources on demand if not initialized yet. + * @see #start() */ public LoopResources getLoopResources() { - Assert.state(this.loopResources != null, "LoopResources not initialized yet"); - return this.loopResources; + if (this.loopResources == null) { + start(); + } + LoopResources loopResources = this.loopResources; + Assert.state(loopResources != null, "LoopResources not initialized"); + return loopResources; } /** @@ -220,6 +232,12 @@ public class ReactorResourceFactory } + /** + * Starts the resources if initialized outside an ApplicationContext. + * This is for backwards compatibility; the preferred way is to rely on + * the ApplicationContext's {@link SmartLifecycle lifecycle management}. + * @see #start() + */ @Override public void afterPropertiesSet() { if (this.applicationContext == null) { @@ -227,6 +245,12 @@ public class ReactorResourceFactory } } + /** + * Stops the resources if initialized outside an ApplicationContext. + * This is for backwards compatibility; the preferred way is to rely on + * the ApplicationContext's {@link SmartLifecycle lifecycle management}. + * @see #stop() + */ @Override public void destroy() { if (this.applicationContext == null) { diff --git a/spring-web/src/test/java/org/springframework/http/client/ReactorResourceFactoryTests.java b/spring-web/src/test/java/org/springframework/http/client/ReactorResourceFactoryTests.java index a08c8983a6b..86d65e64ef9 100644 --- a/spring-web/src/test/java/org/springframework/http/client/ReactorResourceFactoryTests.java +++ b/spring-web/src/test/java/org/springframework/http/client/ReactorResourceFactoryTests.java @@ -261,4 +261,22 @@ class ReactorResourceFactoryTests { assertThat(resourceFactory.isRunning()).isFalse(); } + @Test + void lazilyStartOnConnectionProviderAccess() { + assertThat(this.resourceFactory.isRunning()).isFalse(); + this.resourceFactory.getConnectionProvider(); + assertThat(this.resourceFactory.isRunning()).isTrue(); + this.resourceFactory.stop(); + assertThat(this.resourceFactory.isRunning()).isFalse(); + } + + @Test + void lazilyStartOnLoopResourcesAccess() { + assertThat(this.resourceFactory.isRunning()).isFalse(); + this.resourceFactory.getLoopResources(); + assertThat(this.resourceFactory.isRunning()).isTrue(); + this.resourceFactory.stop(); + assertThat(this.resourceFactory.isRunning()).isFalse(); + } + }