Skip to content

Commit 3305485

Browse files
committed
Merge branch '6.1.x'
2 parents 667b74b + 7785f94 commit 3305485

File tree

6 files changed

+146
-127
lines changed

6 files changed

+146
-127
lines changed

spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java

+14-7
Original file line numberDiff line numberDiff line change
@@ -488,20 +488,27 @@ public int countAdvicesOfType(@Nullable Class<?> adviceClass) {
488488
* @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
489489
*/
490490
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
491-
if (this.methodCache == null) {
491+
List<Object> cachedInterceptors;
492+
if (this.methodCache != null) {
493+
// Method-specific cache for method-specific pointcuts
494+
MethodCacheKey cacheKey = new MethodCacheKey(method);
495+
cachedInterceptors = this.methodCache.get(cacheKey);
496+
if (cachedInterceptors == null) {
497+
cachedInterceptors = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
498+
this, method, targetClass);
499+
this.methodCache.put(cacheKey, cachedInterceptors);
500+
}
501+
}
502+
else {
492503
// Shared cache since there are no method-specific advisors (see below).
493-
List<Object> cachedInterceptors = this.cachedInterceptors;
504+
cachedInterceptors = this.cachedInterceptors;
494505
if (cachedInterceptors == null) {
495506
cachedInterceptors = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
496507
this, method, targetClass);
497508
this.cachedInterceptors = cachedInterceptors;
498509
}
499-
return cachedInterceptors;
500510
}
501-
502-
// Method-specific cache for method-specific pointcuts
503-
return this.methodCache.computeIfAbsent(new MethodCacheKey(method), k ->
504-
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass));
511+
return cachedInterceptors;
505512
}
506513

507514
/**

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

+43-49
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,21 @@ public class ReactorNettyClientRequestFactory implements ClientHttpRequestFactor
5050
private static final Function<HttpClient, HttpClient> defaultInitializer = client -> client.compress(true);
5151

5252

53-
private HttpClient httpClient;
54-
5553
@Nullable
5654
private final ReactorResourceFactory resourceFactory;
5755

5856
@Nullable
5957
private final Function<HttpClient, HttpClient> mapper;
6058

61-
private Duration exchangeTimeout = Duration.ofSeconds(5);
59+
@Nullable
60+
private Integer connectTimeout;
6261

6362
private Duration readTimeout = Duration.ofSeconds(10);
6463

65-
private volatile boolean running = true;
64+
private Duration exchangeTimeout = Duration.ofSeconds(5);
65+
66+
@Nullable
67+
private volatile HttpClient httpClient;
6668

6769
private final Object lifecycleMonitor = new Object();
6870

@@ -107,25 +109,11 @@ public ReactorNettyClientRequestFactory(HttpClient httpClient) {
107109
* @param mapper a mapper for further initialization of the created client
108110
*/
109111
public ReactorNettyClientRequestFactory(ReactorResourceFactory resourceFactory, Function<HttpClient, HttpClient> mapper) {
110-
this.httpClient = createHttpClient(resourceFactory, mapper);
111112
this.resourceFactory = resourceFactory;
112113
this.mapper = mapper;
113-
}
114-
115-
116-
private static HttpClient createHttpClient(ReactorResourceFactory resourceFactory, Function<HttpClient, HttpClient> mapper) {
117-
ConnectionProvider provider = resourceFactory.getConnectionProvider();
118-
Assert.notNull(provider, "No ConnectionProvider: is ReactorResourceFactory not initialized yet?");
119-
return defaultInitializer.andThen(mapper).andThen(applyLoopResources(resourceFactory))
120-
.apply(HttpClient.create(provider));
121-
}
122-
123-
private static Function<HttpClient, HttpClient> applyLoopResources(ReactorResourceFactory factory) {
124-
return httpClient -> {
125-
LoopResources resources = factory.getLoopResources();
126-
Assert.notNull(resources, "No LoopResources: is ReactorResourceFactory not initialized yet?");
127-
return httpClient.runOn(resources);
128-
};
114+
if (resourceFactory.isRunning()) {
115+
this.httpClient = createHttpClient(resourceFactory, mapper);
116+
}
129117
}
130118

131119

@@ -138,7 +126,11 @@ private static Function<HttpClient, HttpClient> applyLoopResources(ReactorResour
138126
*/
139127
public void setConnectTimeout(int connectTimeout) {
140128
Assert.isTrue(connectTimeout >= 0, "Timeout must be a non-negative value");
141-
this.httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
129+
this.connectTimeout = connectTimeout;
130+
HttpClient httpClient = this.httpClient;
131+
if (httpClient != null) {
132+
this.httpClient = httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.connectTimeout);
133+
}
142134
}
143135

144136
/**
@@ -150,8 +142,7 @@ public void setConnectTimeout(int connectTimeout) {
150142
*/
151143
public void setConnectTimeout(Duration connectTimeout) {
152144
Assert.notNull(connectTimeout, "ConnectTimeout must not be null");
153-
Assert.isTrue(!connectTimeout.isNegative(), "Timeout must be a non-negative value");
154-
this.httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int)connectTimeout.toMillis());
145+
setConnectTimeout((int) connectTimeout.toMillis());
155146
}
156147

157148
/**
@@ -192,52 +183,55 @@ public void setExchangeTimeout(Duration exchangeTimeout) {
192183
this.exchangeTimeout = exchangeTimeout;
193184
}
194185

186+
private HttpClient createHttpClient(ReactorResourceFactory factory, Function<HttpClient, HttpClient> mapper) {
187+
HttpClient httpClient = defaultInitializer.andThen(mapper)
188+
.apply(HttpClient.create(factory.getConnectionProvider()));
189+
httpClient = httpClient.runOn(factory.getLoopResources());
190+
if (this.connectTimeout != null) {
191+
httpClient = httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.connectTimeout);
192+
}
193+
return httpClient;
194+
}
195+
195196

196197
@Override
197198
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
198-
return new ReactorNettyClientRequest(this.httpClient, uri, httpMethod, this.exchangeTimeout, this.readTimeout);
199+
HttpClient httpClient = this.httpClient;
200+
if (httpClient == null) {
201+
Assert.state(this.resourceFactory != null && this.mapper != null, "Illegal configuration");
202+
httpClient = createHttpClient(this.resourceFactory, this.mapper);
203+
}
204+
return new ReactorNettyClientRequest(httpClient, uri, httpMethod, this.exchangeTimeout, this.readTimeout);
199205
}
200206

207+
201208
@Override
202209
public void start() {
203-
synchronized (this.lifecycleMonitor) {
204-
if (!isRunning()) {
205-
if (this.resourceFactory != null && this.mapper != null) {
210+
if (this.resourceFactory != null && this.mapper != null) {
211+
synchronized (this.lifecycleMonitor) {
212+
if (this.httpClient == null) {
206213
this.httpClient = createHttpClient(this.resourceFactory, this.mapper);
207214
}
208-
else {
209-
logger.warn("Restarting a ReactorNettyClientRequestFactory bean is only supported with externally managed Reactor Netty resources");
210-
}
211-
this.running = true;
212215
}
213216
}
217+
else {
218+
logger.warn("Restarting a ReactorNettyClientRequestFactory bean is only supported " +
219+
"with externally managed Reactor Netty resources");
220+
}
214221
}
215222

216223
@Override
217224
public void stop() {
218-
synchronized (this.lifecycleMonitor) {
219-
if (isRunning()) {
220-
this.running = false;
225+
if (this.resourceFactory != null && this.mapper != null) {
226+
synchronized (this.lifecycleMonitor) {
227+
this.httpClient = null;
221228
}
222229
}
223230
}
224231

225-
@Override
226-
public final void stop(Runnable callback) {
227-
synchronized (this.lifecycleMonitor) {
228-
stop();
229-
callback.run();
230-
}
231-
}
232-
233232
@Override
234233
public boolean isRunning() {
235-
return this.running;
236-
}
237-
238-
@Override
239-
public boolean isAutoStartup() {
240-
return false;
234+
return (this.httpClient != null);
241235
}
242236

243237
@Override

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ public void destroy() {
237237
@Override
238238
public void start() {
239239
synchronized (this.lifecycleMonitor) {
240-
if (!isRunning()) {
240+
if (!this.running) {
241241
if (this.useGlobalResources) {
242242
Assert.isTrue(this.loopResources == null && this.connectionProvider == null,
243243
"'useGlobalResources' is mutually exclusive with explicitly configured resources");
@@ -267,7 +267,7 @@ public void start() {
267267
@Override
268268
public void stop() {
269269
synchronized (this.lifecycleMonitor) {
270-
if (isRunning()) {
270+
if (this.running) {
271271
if (this.useGlobalResources) {
272272
HttpResources.disposeLoopsAndConnectionsLater(this.shutdownQuietPeriod, this.shutdownTimeout).block();
273273
this.connectionProvider = null;
@@ -306,4 +306,10 @@ public boolean isRunning() {
306306
return this.running;
307307
}
308308

309+
@Override
310+
public int getPhase() {
311+
// Same as plain Lifecycle
312+
return 0;
313+
}
314+
309315
}

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

+40-59
Original file line numberDiff line numberDiff line change
@@ -63,31 +63,40 @@ public class ReactorClientHttpConnector implements ClientHttpConnector, SmartLif
6363
private static final Function<HttpClient, HttpClient> defaultInitializer = client -> client.compress(true);
6464

6565

66-
private HttpClient httpClient;
67-
6866
@Nullable
6967
private final ReactorResourceFactory resourceFactory;
7068

7169
@Nullable
7270
private final Function<HttpClient, HttpClient> mapper;
7371

74-
private volatile boolean running = true;
72+
@Nullable
73+
private volatile HttpClient httpClient;
7574

7675
private final Object lifecycleMonitor = new Object();
7776

7877

7978
/**
8079
* Default constructor. Initializes {@link HttpClient} via:
81-
* <pre class="code">
82-
* HttpClient.create().compress()
83-
* </pre>
80+
* <pre class="code">HttpClient.create().compress(true)</pre>
8481
*/
8582
public ReactorClientHttpConnector() {
8683
this.httpClient = defaultInitializer.apply(HttpClient.create());
8784
this.resourceFactory = null;
8885
this.mapper = null;
8986
}
9087

88+
/**
89+
* Constructor with a pre-configured {@code HttpClient} instance.
90+
* @param httpClient the client to use
91+
* @since 5.1
92+
*/
93+
public ReactorClientHttpConnector(HttpClient httpClient) {
94+
Assert.notNull(httpClient, "HttpClient is required");
95+
this.httpClient = httpClient;
96+
this.resourceFactory = null;
97+
this.mapper = null;
98+
}
99+
91100
/**
92101
* Constructor with externally managed Reactor Netty resources, including
93102
* {@link LoopResources} for event loop threads, and {@link ConnectionProvider}
@@ -107,50 +116,34 @@ public ReactorClientHttpConnector() {
107116
* @since 5.1
108117
*/
109118
public ReactorClientHttpConnector(ReactorResourceFactory resourceFactory, Function<HttpClient, HttpClient> mapper) {
110-
this.httpClient = createHttpClient(resourceFactory, mapper);
111119
this.resourceFactory = resourceFactory;
112120
this.mapper = mapper;
121+
if (resourceFactory.isRunning()) {
122+
this.httpClient = createHttpClient(resourceFactory, mapper);
123+
}
113124
}
114125

115-
private static HttpClient createHttpClient(ReactorResourceFactory resourceFactory, Function<HttpClient, HttpClient> mapper) {
116-
ConnectionProvider provider = resourceFactory.getConnectionProvider();
117-
Assert.notNull(provider, "No ConnectionProvider: is ReactorResourceFactory not initialized yet?");
118-
return defaultInitializer.andThen(mapper).andThen(applyLoopResources(resourceFactory))
119-
.apply(HttpClient.create(provider));
120-
}
121-
122-
private static Function<HttpClient, HttpClient> applyLoopResources(ReactorResourceFactory factory) {
123-
return httpClient -> {
124-
LoopResources resources = factory.getLoopResources();
125-
Assert.notNull(resources, "No LoopResources: is ReactorResourceFactory not initialized yet?");
126-
return httpClient.runOn(resources);
127-
};
128-
}
129-
130-
131-
/**
132-
* Constructor with a pre-configured {@code HttpClient} instance.
133-
* @param httpClient the client to use
134-
* @since 5.1
135-
*/
136-
public ReactorClientHttpConnector(HttpClient httpClient) {
137-
Assert.notNull(httpClient, "HttpClient is required");
138-
this.httpClient = httpClient;
139-
this.resourceFactory = null;
140-
this.mapper = null;
126+
private static HttpClient createHttpClient(ReactorResourceFactory factory, Function<HttpClient, HttpClient> mapper) {
127+
return defaultInitializer.andThen(mapper).andThen(httpClient -> httpClient.runOn(factory.getLoopResources()))
128+
.apply(HttpClient.create(factory.getConnectionProvider()));
141129
}
142130

143131

144132
@Override
145133
public Mono<ClientHttpResponse> connect(HttpMethod method, URI uri,
146134
Function<? super ClientHttpRequest, Mono<Void>> requestCallback) {
147135

148-
AtomicReference<ReactorClientHttpResponse> responseRef = new AtomicReference<>();
136+
HttpClient httpClient = this.httpClient;
137+
if (httpClient == null) {
138+
Assert.state(this.resourceFactory != null && this.mapper != null, "Illegal configuration");
139+
httpClient = createHttpClient(this.resourceFactory, this.mapper);
140+
}
149141

150-
HttpClient.RequestSender requestSender = this.httpClient
142+
HttpClient.RequestSender requestSender = httpClient
151143
.request(io.netty.handler.codec.http.HttpMethod.valueOf(method.name()));
152144

153145
requestSender = setUri(requestSender, uri);
146+
AtomicReference<ReactorClientHttpResponse> responseRef = new AtomicReference<>();
154147

155148
return requestSender
156149
.send((request, outbound) -> requestCallback.apply(adaptRequest(method, uri, request, outbound)))
@@ -185,46 +178,34 @@ private ReactorClientHttpRequest adaptRequest(HttpMethod method, URI uri, HttpCl
185178
return new ReactorClientHttpRequest(method, uri, request, nettyOutbound);
186179
}
187180

181+
188182
@Override
189183
public void start() {
190-
synchronized (this.lifecycleMonitor) {
191-
if (!isRunning()) {
192-
if (this.resourceFactory != null && this.mapper != null) {
184+
if (this.resourceFactory != null && this.mapper != null) {
185+
synchronized (this.lifecycleMonitor) {
186+
if (this.httpClient == null) {
193187
this.httpClient = createHttpClient(this.resourceFactory, this.mapper);
194188
}
195-
else {
196-
logger.warn("Restarting a ReactorClientHttpConnector bean is only supported with externally managed Reactor Netty resources");
197-
}
198-
this.running = true;
199189
}
200190
}
191+
else {
192+
logger.warn("Restarting a ReactorClientHttpConnector bean is only supported " +
193+
"with externally managed Reactor Netty resources");
194+
}
201195
}
202196

203197
@Override
204198
public void stop() {
205-
synchronized (this.lifecycleMonitor) {
206-
if (isRunning()) {
207-
this.running = false;
199+
if (this.resourceFactory != null && this.mapper != null) {
200+
synchronized (this.lifecycleMonitor) {
201+
this.httpClient = null;
208202
}
209203
}
210204
}
211205

212-
@Override
213-
public final void stop(Runnable callback) {
214-
synchronized (this.lifecycleMonitor) {
215-
stop();
216-
callback.run();
217-
}
218-
}
219-
220206
@Override
221207
public boolean isRunning() {
222-
return this.running;
223-
}
224-
225-
@Override
226-
public boolean isAutoStartup() {
227-
return false;
208+
return (this.httpClient != null);
228209
}
229210

230211
@Override

0 commit comments

Comments
 (0)