20
20
import java .util .concurrent .atomic .AtomicReference ;
21
21
import java .util .function .Function ;
22
22
23
+ import org .apache .commons .logging .Log ;
24
+ import org .apache .commons .logging .LogFactory ;
23
25
import reactor .core .publisher .Mono ;
24
26
import reactor .netty .NettyOutbound ;
25
27
import reactor .netty .http .client .HttpClient ;
26
28
import reactor .netty .http .client .HttpClientRequest ;
27
29
import reactor .netty .resources .ConnectionProvider ;
28
30
import reactor .netty .resources .LoopResources ;
29
31
32
+ import org .springframework .context .Lifecycle ;
33
+ import org .springframework .context .SmartLifecycle ;
30
34
import org .springframework .http .HttpMethod ;
35
+ import org .springframework .lang .Nullable ;
31
36
import org .springframework .util .Assert ;
32
37
33
38
/**
34
39
* Reactor-Netty implementation of {@link ClientHttpConnector}.
35
40
*
41
+ * <p>This class implements {@link Lifecycle} and can be optionally declared
42
+ * as a Spring-managed bean.
43
+ *
36
44
* @author Brian Clozel
37
45
* @author Rossen Stoyanchev
46
+ * @author Sebastien Deleuze
38
47
* @since 5.0
39
48
* @see reactor.netty.http.client.HttpClient
40
49
*/
41
- public class ReactorClientHttpConnector implements ClientHttpConnector {
50
+ public class ReactorClientHttpConnector implements ClientHttpConnector , SmartLifecycle {
51
+
52
+ private static final Log logger = LogFactory .getLog (ReactorClientHttpConnector .class );
42
53
43
54
private final static Function <HttpClient , HttpClient > defaultInitializer = client -> client .compress (true );
44
55
45
56
46
- private final HttpClient httpClient ;
57
+ private HttpClient httpClient ;
58
+
59
+ @ Nullable
60
+ private final ReactorResourceFactory resourceFactory ;
61
+
62
+ @ Nullable
63
+ private final Function <HttpClient , HttpClient > mapper ;
64
+
65
+ private volatile boolean running = true ;
66
+
67
+ private final Object lifecycleMonitor = new Object ();
47
68
48
69
49
70
/**
@@ -54,6 +75,8 @@ public class ReactorClientHttpConnector implements ClientHttpConnector {
54
75
*/
55
76
public ReactorClientHttpConnector () {
56
77
this .httpClient = defaultInitializer .apply (HttpClient .create ());
78
+ this .resourceFactory = null ;
79
+ this .mapper = null ;
57
80
}
58
81
59
82
/**
@@ -68,14 +91,20 @@ public ReactorClientHttpConnector() {
68
91
* consider declaring a {@link ReactorResourceFactory} bean with
69
92
* {@code globalResources=true} in order to ensure the Reactor Netty global
70
93
* resources are shut down when the Spring ApplicationContext is closed.
71
- * @param factory the resource factory to obtain the resources from
94
+ * @param resourceFactory the resource factory to obtain the resources from
72
95
* @param mapper a mapper for further initialization of the created client
73
96
* @since 5.1
74
97
*/
75
- public ReactorClientHttpConnector (ReactorResourceFactory factory , Function <HttpClient , HttpClient > mapper ) {
76
- ConnectionProvider provider = factory .getConnectionProvider ();
98
+ public ReactorClientHttpConnector (ReactorResourceFactory resourceFactory , Function <HttpClient , HttpClient > mapper ) {
99
+ this .httpClient = createHttpClient (resourceFactory , mapper );
100
+ this .resourceFactory = resourceFactory ;
101
+ this .mapper = mapper ;
102
+ }
103
+
104
+ private static HttpClient createHttpClient (ReactorResourceFactory resourceFactory , Function <HttpClient , HttpClient > mapper ) {
105
+ ConnectionProvider provider = resourceFactory .getConnectionProvider ();
77
106
Assert .notNull (provider , "No ConnectionProvider: is ReactorResourceFactory not initialized yet?" );
78
- this . httpClient = defaultInitializer .andThen (mapper ).andThen (applyLoopResources (factory ))
107
+ return defaultInitializer .andThen (mapper ).andThen (applyLoopResources (resourceFactory ))
79
108
.apply (HttpClient .create (provider ));
80
109
}
81
110
@@ -96,6 +125,8 @@ private static Function<HttpClient, HttpClient> applyLoopResources(ReactorResour
96
125
public ReactorClientHttpConnector (HttpClient httpClient ) {
97
126
Assert .notNull (httpClient , "HttpClient is required" );
98
127
this .httpClient = httpClient ;
128
+ this .resourceFactory = null ;
129
+ this .mapper = null ;
99
130
}
100
131
101
132
@@ -131,4 +162,52 @@ private ReactorClientHttpRequest adaptRequest(HttpMethod method, URI uri, HttpCl
131
162
return new ReactorClientHttpRequest (method , uri , request , nettyOutbound );
132
163
}
133
164
165
+ @ Override
166
+ public void start () {
167
+ synchronized (this .lifecycleMonitor ) {
168
+ if (!isRunning ()) {
169
+ if (this .resourceFactory != null && this .mapper != null ) {
170
+ this .httpClient = createHttpClient (this .resourceFactory , this .mapper );
171
+ }
172
+ else {
173
+ logger .warn ("Restarting a ReactorClientHttpConnector bean is only supported with externally managed Reactor Netty resources" );
174
+ }
175
+ this .running = true ;
176
+ }
177
+ }
178
+ }
179
+
180
+ @ Override
181
+ public void stop () {
182
+ synchronized (this .lifecycleMonitor ) {
183
+ if (isRunning ()) {
184
+ this .running = false ;
185
+ }
186
+ }
187
+ }
188
+
189
+ @ Override
190
+ public final void stop (Runnable callback ) {
191
+ synchronized (this .lifecycleMonitor ) {
192
+ stop ();
193
+ callback .run ();
194
+ }
195
+ }
196
+
197
+ @ Override
198
+ public boolean isRunning () {
199
+ return this .running ;
200
+ }
201
+
202
+ @ Override
203
+ public boolean isAutoStartup () {
204
+ return false ;
205
+ }
206
+
207
+ @ Override
208
+ public int getPhase () {
209
+ // Start after ReactorResourceFactory
210
+ return 1 ;
211
+ }
212
+
134
213
}
0 commit comments