Refine ReactorResourceFactory
1. Rename globalResources to useGlobalResources. 2. Use of global resources is mutually exlusive with explicit config. 3. Allow Consumer<HttpResources> to configure global resources. 4. Allow ConnectionProvider + LoopResources Supplier to customize creation and initialization. 5. Do not manage externally provided ConnectionProvider + LoopResources instances. Issue: SPR-17243
This commit is contained in:
parent
3302798e2f
commit
d537a1cfb4
|
@ -15,6 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.http.client.reactive;
|
package org.springframework.http.client.reactive;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import reactor.netty.http.HttpResources;
|
import reactor.netty.http.HttpResources;
|
||||||
import reactor.netty.resources.ConnectionProvider;
|
import reactor.netty.resources.ConnectionProvider;
|
||||||
import reactor.netty.resources.LoopResources;
|
import reactor.netty.resources.LoopResources;
|
||||||
|
@ -37,7 +40,16 @@ import org.springframework.util.Assert;
|
||||||
*/
|
*/
|
||||||
public class ReactorResourceFactory implements InitializingBean, DisposableBean {
|
public class ReactorResourceFactory implements InitializingBean, DisposableBean {
|
||||||
|
|
||||||
private boolean globalResources = true;
|
private boolean useGlobalResources = true;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Consumer<HttpResources> globalResourcesConsumer;
|
||||||
|
|
||||||
|
|
||||||
|
private Supplier<ConnectionProvider> connectionProviderSupplier = () -> ConnectionProvider.elastic("http");
|
||||||
|
|
||||||
|
private Supplier<LoopResources> loopResourcesSupplier = () -> LoopResources.create("reactor-http");
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ConnectionProvider connectionProvider;
|
private ConnectionProvider connectionProvider;
|
||||||
|
@ -45,110 +57,137 @@ public class ReactorResourceFactory implements InitializingBean, DisposableBean
|
||||||
@Nullable
|
@Nullable
|
||||||
private LoopResources loopResources;
|
private LoopResources loopResources;
|
||||||
|
|
||||||
private String threadPrefix = "reactor-http";
|
|
||||||
|
private boolean manageConnectionProvider = false;
|
||||||
|
|
||||||
|
private boolean manageLoopResources = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to expose and manage the global Reactor Netty resources from the
|
* Whether to use global Reactor Netty resources via {@link HttpResources}.
|
||||||
* {@link HttpResources} holder.
|
* <p>Default is "true" in which case this factory initializes and stops the
|
||||||
* <p>Default is "true" in which case this factory helps to configure and
|
* global Reactor Netty resources within Spring's {@code ApplicationContext}
|
||||||
* shut down the global Reactor Netty resources within the lifecycle of a
|
* lifecycle. If set to "false" the factory manages its resources independent
|
||||||
* Spring {@code ApplicationContext}.
|
* of the global ones.
|
||||||
* <p>If set to "false" then the factory creates and manages its own
|
* @param useGlobalResources whether to expose and manage the global resources
|
||||||
* {@link LoopResources} and {@link ConnectionProvider}, independent of the
|
* @see #addGlobalResourcesConsumer(Consumer)
|
||||||
* global ones in the {@link HttpResources} holder.
|
|
||||||
* @param globalResources whether to expose and manage the global resources
|
|
||||||
*/
|
*/
|
||||||
public void setGlobalResources(boolean globalResources) {
|
public void setUseGlobalResources(boolean useGlobalResources) {
|
||||||
this.globalResources = globalResources;
|
this.useGlobalResources = useGlobalResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the {@link ConnectionProvider} to use.
|
* Add a Consumer for configuring the global Reactor Netty resources on
|
||||||
* <p>By default, initialized with {@link ConnectionProvider#elastic(String)}.
|
* startup. When this option is used, {@link #setUseGlobalResources} is also
|
||||||
* @param connectionProvider the connection provider to use
|
* enabled.
|
||||||
|
* @param consumer the consumer to apply
|
||||||
|
* @see #setUseGlobalResources(boolean)
|
||||||
|
*/
|
||||||
|
public void addGlobalResourcesConsumer(Consumer<HttpResources> consumer) {
|
||||||
|
this.useGlobalResources = true;
|
||||||
|
this.globalResourcesConsumer = this.globalResourcesConsumer != null ?
|
||||||
|
this.globalResourcesConsumer.andThen(consumer) : consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this option when you don't want to participate in global resources and
|
||||||
|
* you want to customize the creation of the managed {@code ConnectionProvider}.
|
||||||
|
* <p>By default, {@code ConnectionProvider.elastic("http")} is used.
|
||||||
|
* <p>Note that this option is ignored if {@code userGlobalResources=false} or
|
||||||
|
* {@link #setConnectionProvider(ConnectionProvider)} is set.
|
||||||
|
* @param supplier the supplier to use
|
||||||
|
*/
|
||||||
|
public void setConnectionProviderSupplier(@Nullable Supplier<ConnectionProvider> supplier) {
|
||||||
|
this.connectionProviderSupplier = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this option when you don't want to participate in global resources and
|
||||||
|
* you want to customize the creation of the managed {@code LoopResources}.
|
||||||
|
* <p>By default, {@code LoopResources.create("reactor-http")} is used.
|
||||||
|
* <p>Note that this option is ignored if {@code userGlobalResources=false} or
|
||||||
|
* {@link #setLoopResources(LoopResources)} is set.
|
||||||
|
* @param supplier the supplier to use
|
||||||
|
*/
|
||||||
|
public void setLoopResourcesSupplier(@Nullable Supplier<LoopResources> supplier) {
|
||||||
|
this.loopResourcesSupplier = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this option when you want to provide an externally managed
|
||||||
|
* {@link ConnectionProvider} instance.
|
||||||
|
* @param connectionProvider the connection provider to use as is
|
||||||
*/
|
*/
|
||||||
public void setConnectionProvider(@Nullable ConnectionProvider connectionProvider) {
|
public void setConnectionProvider(@Nullable ConnectionProvider connectionProvider) {
|
||||||
this.connectionProvider = connectionProvider;
|
this.connectionProvider = connectionProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the {@link LoopResources} to use.
|
* Use this option when you want to provide an externally managed
|
||||||
* <p>By default, initialized with {@link LoopResources#create(String)}.
|
* {@link LoopResources} instance.
|
||||||
* @param loopResources the loop resources to use
|
* @param loopResources the loop resources to use as is
|
||||||
*/
|
*/
|
||||||
public void setLoopResources(@Nullable LoopResources loopResources) {
|
public void setLoopResources(@Nullable LoopResources loopResources) {
|
||||||
this.loopResources = loopResources;
|
this.loopResources = loopResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the thread prefix to initialize {@link LoopResources} with. This
|
|
||||||
* is used only when a {@link LoopResources} instance isn't
|
|
||||||
* {@link #setLoopResources(LoopResources) provided}.
|
|
||||||
* <p>By default set to "reactor-http".
|
|
||||||
* @param threadPrefix the thread prefix to use
|
|
||||||
*/
|
|
||||||
public void setThreadPrefix(String threadPrefix) {
|
|
||||||
Assert.notNull(threadPrefix, "Thread prefix is required");
|
|
||||||
this.threadPrefix = threadPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this factory exposes the global
|
* Whether this factory exposes the global
|
||||||
* {@link reactor.netty.http.HttpResources HttpResources} holder.
|
* {@link reactor.netty.http.HttpResources HttpResources} holder.
|
||||||
*/
|
*/
|
||||||
public boolean isGlobalResources() {
|
public boolean isUseGlobalResources() {
|
||||||
return this.globalResources;
|
return this.useGlobalResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the configured {@link ConnectionProvider}.
|
* Return the configured {@link ConnectionProvider}.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
|
||||||
public ConnectionProvider getConnectionProvider() {
|
public ConnectionProvider getConnectionProvider() {
|
||||||
|
Assert.notNull(this.connectionProvider, "ConnectionProvider not initialized yet via InitializingBean.");
|
||||||
return this.connectionProvider;
|
return this.connectionProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the configured {@link LoopResources}.
|
* Return the configured {@link LoopResources}.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
|
||||||
public LoopResources getLoopResources() {
|
public LoopResources getLoopResources() {
|
||||||
|
Assert.notNull(this.loopResources, "LoopResources not initialized yet via InitializingBean.");
|
||||||
return this.loopResources;
|
return this.loopResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the configured prefix for event loop threads.
|
|
||||||
*/
|
|
||||||
public String getThreadPrefix() {
|
|
||||||
return this.threadPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
if (this.useGlobalResources) {
|
||||||
|
Assert.isTrue(this.loopResources == null && this.connectionProvider == null,
|
||||||
|
"'useGlobalResources' is mutually exclusive with explicitly configured resources.");
|
||||||
|
HttpResources httpResources = HttpResources.get();
|
||||||
|
if (this.globalResourcesConsumer != null) {
|
||||||
|
this.globalResourcesConsumer.accept(httpResources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (this.loopResources == null) {
|
if (this.loopResources == null) {
|
||||||
this.loopResources = LoopResources.create(this.threadPrefix);
|
this.manageLoopResources = true;
|
||||||
|
this.loopResources = this.loopResourcesSupplier.get();
|
||||||
}
|
}
|
||||||
if (this.connectionProvider == null) {
|
if (this.connectionProvider == null) {
|
||||||
this.connectionProvider = ConnectionProvider.elastic("http");
|
this.manageConnectionProvider = true;
|
||||||
|
this.connectionProvider = this.connectionProviderSupplier.get();
|
||||||
}
|
}
|
||||||
if (this.globalResources) {
|
|
||||||
HttpResources.set(this.loopResources);
|
|
||||||
HttpResources.set(this.connectionProvider);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
if (this.globalResources) {
|
if (this.useGlobalResources) {
|
||||||
HttpResources.disposeLoopsAndConnections();
|
HttpResources.disposeLoopsAndConnections();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
ConnectionProvider provider = this.connectionProvider;
|
ConnectionProvider provider = this.connectionProvider;
|
||||||
if (provider != null) {
|
if (provider != null && this.manageConnectionProvider) {
|
||||||
provider.dispose();
|
provider.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +197,7 @@ public class ReactorResourceFactory implements InitializingBean, DisposableBean
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LoopResources resources = this.loopResources;
|
LoopResources resources = this.loopResources;
|
||||||
if (resources != null) {
|
if (resources != null && this.manageLoopResources) {
|
||||||
resources.dispose();
|
resources.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ concurrency. In this mode global resources remain active until the process exits
|
||||||
If the server is timed with the process, there is typically no need for an explicit
|
If the server is timed with the process, there is typically no need for an explicit
|
||||||
shutdown. However if the server can start or stop in-process, e.g. Spring MVC
|
shutdown. However if the server can start or stop in-process, e.g. Spring MVC
|
||||||
application deployed as a WAR, you can declare a Spring-managed bean of type
|
application deployed as a WAR, you can declare a Spring-managed bean of type
|
||||||
`ReactorResourceFactory` with `globalResources=true` (the default) to ensure the Reactor
|
`ReactorResourceFactory` with `useGlobalResources=true` (the default) to ensure the Reactor
|
||||||
Netty global resources are shut down when the Spring `ApplicationContext` is closed:
|
Netty global resources are shut down when the Spring `ApplicationContext` is closed:
|
||||||
|
|
||||||
[source,java,intent=0]
|
[source,java,intent=0]
|
||||||
|
|
Loading…
Reference in New Issue