Skip to content

Commit d537a1c

Browse files
committed
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
1 parent 3302798 commit d537a1c

File tree

2 files changed

+93
-54
lines changed

2 files changed

+93
-54
lines changed

spring-web/src/main/java/org/springframework/http/client/reactive/ReactorResourceFactory.java

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package org.springframework.http.client.reactive;
1717

18+
import java.util.function.Consumer;
19+
import java.util.function.Supplier;
20+
1821
import reactor.netty.http.HttpResources;
1922
import reactor.netty.resources.ConnectionProvider;
2023
import reactor.netty.resources.LoopResources;
@@ -37,118 +40,154 @@
3740
*/
3841
public class ReactorResourceFactory implements InitializingBean, DisposableBean {
3942

40-
private boolean globalResources = true;
43+
private boolean useGlobalResources = true;
44+
45+
@Nullable
46+
private Consumer<HttpResources> globalResourcesConsumer;
47+
48+
49+
private Supplier<ConnectionProvider> connectionProviderSupplier = () -> ConnectionProvider.elastic("http");
50+
51+
private Supplier<LoopResources> loopResourcesSupplier = () -> LoopResources.create("reactor-http");
52+
4153

4254
@Nullable
4355
private ConnectionProvider connectionProvider;
4456

4557
@Nullable
4658
private LoopResources loopResources;
4759

48-
private String threadPrefix = "reactor-http";
60+
61+
private boolean manageConnectionProvider = false;
62+
63+
private boolean manageLoopResources = false;
4964

5065

5166
/**
52-
* Whether to expose and manage the global Reactor Netty resources from the
53-
* {@link HttpResources} holder.
54-
* <p>Default is "true" in which case this factory helps to configure and
55-
* shut down the global Reactor Netty resources within the lifecycle of a
56-
* Spring {@code ApplicationContext}.
57-
* <p>If set to "false" then the factory creates and manages its own
58-
* {@link LoopResources} and {@link ConnectionProvider}, independent of the
59-
* global ones in the {@link HttpResources} holder.
60-
* @param globalResources whether to expose and manage the global resources
67+
* Whether to use global Reactor Netty resources via {@link HttpResources}.
68+
* <p>Default is "true" in which case this factory initializes and stops the
69+
* global Reactor Netty resources within Spring's {@code ApplicationContext}
70+
* lifecycle. If set to "false" the factory manages its resources independent
71+
* of the global ones.
72+
* @param useGlobalResources whether to expose and manage the global resources
73+
* @see #addGlobalResourcesConsumer(Consumer)
6174
*/
62-
public void setGlobalResources(boolean globalResources) {
63-
this.globalResources = globalResources;
75+
public void setUseGlobalResources(boolean useGlobalResources) {
76+
this.useGlobalResources = useGlobalResources;
6477
}
6578

6679
/**
67-
* Configure the {@link ConnectionProvider} to use.
68-
* <p>By default, initialized with {@link ConnectionProvider#elastic(String)}.
69-
* @param connectionProvider the connection provider to use
80+
* Add a Consumer for configuring the global Reactor Netty resources on
81+
* startup. When this option is used, {@link #setUseGlobalResources} is also
82+
* enabled.
83+
* @param consumer the consumer to apply
84+
* @see #setUseGlobalResources(boolean)
7085
*/
71-
public void setConnectionProvider(@Nullable ConnectionProvider connectionProvider) {
72-
this.connectionProvider = connectionProvider;
86+
public void addGlobalResourcesConsumer(Consumer<HttpResources> consumer) {
87+
this.useGlobalResources = true;
88+
this.globalResourcesConsumer = this.globalResourcesConsumer != null ?
89+
this.globalResourcesConsumer.andThen(consumer) : consumer;
7390
}
7491

7592
/**
76-
* Configure the {@link LoopResources} to use.
77-
* <p>By default, initialized with {@link LoopResources#create(String)}.
78-
* @param loopResources the loop resources to use
93+
* Use this option when you don't want to participate in global resources and
94+
* you want to customize the creation of the managed {@code ConnectionProvider}.
95+
* <p>By default, {@code ConnectionProvider.elastic("http")} is used.
96+
* <p>Note that this option is ignored if {@code userGlobalResources=false} or
97+
* {@link #setConnectionProvider(ConnectionProvider)} is set.
98+
* @param supplier the supplier to use
7999
*/
80-
public void setLoopResources(@Nullable LoopResources loopResources) {
81-
this.loopResources = loopResources;
100+
public void setConnectionProviderSupplier(@Nullable Supplier<ConnectionProvider> supplier) {
101+
this.connectionProviderSupplier = supplier;
102+
}
103+
104+
/**
105+
* Use this option when you don't want to participate in global resources and
106+
* you want to customize the creation of the managed {@code LoopResources}.
107+
* <p>By default, {@code LoopResources.create("reactor-http")} is used.
108+
* <p>Note that this option is ignored if {@code userGlobalResources=false} or
109+
* {@link #setLoopResources(LoopResources)} is set.
110+
* @param supplier the supplier to use
111+
*/
112+
public void setLoopResourcesSupplier(@Nullable Supplier<LoopResources> supplier) {
113+
this.loopResourcesSupplier = supplier;
114+
}
115+
116+
/**
117+
* Use this option when you want to provide an externally managed
118+
* {@link ConnectionProvider} instance.
119+
* @param connectionProvider the connection provider to use as is
120+
*/
121+
public void setConnectionProvider(@Nullable ConnectionProvider connectionProvider) {
122+
this.connectionProvider = connectionProvider;
82123
}
83124

84125
/**
85-
* Configure the thread prefix to initialize {@link LoopResources} with. This
86-
* is used only when a {@link LoopResources} instance isn't
87-
* {@link #setLoopResources(LoopResources) provided}.
88-
* <p>By default set to "reactor-http".
89-
* @param threadPrefix the thread prefix to use
126+
* Use this option when you want to provide an externally managed
127+
* {@link LoopResources} instance.
128+
* @param loopResources the loop resources to use as is
90129
*/
91-
public void setThreadPrefix(String threadPrefix) {
92-
Assert.notNull(threadPrefix, "Thread prefix is required");
93-
this.threadPrefix = threadPrefix;
130+
public void setLoopResources(@Nullable LoopResources loopResources) {
131+
this.loopResources = loopResources;
94132
}
95133

96134

97135
/**
98136
* Whether this factory exposes the global
99137
* {@link reactor.netty.http.HttpResources HttpResources} holder.
100138
*/
101-
public boolean isGlobalResources() {
102-
return this.globalResources;
139+
public boolean isUseGlobalResources() {
140+
return this.useGlobalResources;
103141
}
104142

105143
/**
106144
* Return the configured {@link ConnectionProvider}.
107145
*/
108-
@Nullable
109146
public ConnectionProvider getConnectionProvider() {
147+
Assert.notNull(this.connectionProvider, "ConnectionProvider not initialized yet via InitializingBean.");
110148
return this.connectionProvider;
111149
}
112150

113151
/**
114152
* Return the configured {@link LoopResources}.
115153
*/
116-
@Nullable
117154
public LoopResources getLoopResources() {
155+
Assert.notNull(this.loopResources, "LoopResources not initialized yet via InitializingBean.");
118156
return this.loopResources;
119157
}
120158

121-
/**
122-
* Return the configured prefix for event loop threads.
123-
*/
124-
public String getThreadPrefix() {
125-
return this.threadPrefix;
126-
}
127-
128159

129160
@Override
130161
public void afterPropertiesSet() throws Exception {
131-
if (this.loopResources == null) {
132-
this.loopResources = LoopResources.create(this.threadPrefix);
133-
}
134-
if (this.connectionProvider == null) {
135-
this.connectionProvider = ConnectionProvider.elastic("http");
162+
if (this.useGlobalResources) {
163+
Assert.isTrue(this.loopResources == null && this.connectionProvider == null,
164+
"'useGlobalResources' is mutually exclusive with explicitly configured resources.");
165+
HttpResources httpResources = HttpResources.get();
166+
if (this.globalResourcesConsumer != null) {
167+
this.globalResourcesConsumer.accept(httpResources);
168+
}
136169
}
137-
if (this.globalResources) {
138-
HttpResources.set(this.loopResources);
139-
HttpResources.set(this.connectionProvider);
170+
else {
171+
if (this.loopResources == null) {
172+
this.manageLoopResources = true;
173+
this.loopResources = this.loopResourcesSupplier.get();
174+
}
175+
if (this.connectionProvider == null) {
176+
this.manageConnectionProvider = true;
177+
this.connectionProvider = this.connectionProviderSupplier.get();
178+
}
140179
}
141180
}
142181

143182
@Override
144183
public void destroy() {
145-
if (this.globalResources) {
184+
if (this.useGlobalResources) {
146185
HttpResources.disposeLoopsAndConnections();
147186
}
148187
else {
149188
try {
150189
ConnectionProvider provider = this.connectionProvider;
151-
if (provider != null) {
190+
if (provider != null && this.manageConnectionProvider) {
152191
provider.dispose();
153192
}
154193
}
@@ -158,7 +197,7 @@ public void destroy() {
158197

159198
try {
160199
LoopResources resources = this.loopResources;
161-
if (resources != null) {
200+
if (resources != null && this.manageLoopResources) {
162201
resources.dispose();
163202
}
164203
}

src/docs/asciidoc/web/webflux-webclient.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ concurrency. In this mode global resources remain active until the process exits
9494
If the server is timed with the process, there is typically no need for an explicit
9595
shutdown. However if the server can start or stop in-process, e.g. Spring MVC
9696
application deployed as a WAR, you can declare a Spring-managed bean of type
97-
`ReactorResourceFactory` with `globalResources=true` (the default) to ensure the Reactor
97+
`ReactorResourceFactory` with `useGlobalResources=true` (the default) to ensure the Reactor
9898
Netty global resources are shut down when the Spring `ApplicationContext` is closed:
9999

100100
[source,java,intent=0]

0 commit comments

Comments
 (0)