Skip to content

Commit 5099c0f

Browse files
authored
Http2Client: added clients cache (#2405)
1 parent 81168f1 commit 5099c0f

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

java11/src/main/java/feign/http2client/Http2Client.java

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import feign.Util;
2525
import java.io.ByteArrayInputStream;
2626
import java.io.IOException;
27+
import java.lang.ref.SoftReference;
2728
import java.net.URI;
2829
import java.net.URISyntaxException;
2930
import java.net.http.HttpClient;
@@ -48,13 +49,16 @@
4849
import java.util.Set;
4950
import java.util.TreeSet;
5051
import java.util.concurrent.CompletableFuture;
52+
import java.util.concurrent.ConcurrentHashMap;
5153
import java.util.function.Function;
5254
import java.util.stream.Collectors;
5355

5456
public class Http2Client implements Client, AsyncClient<Object> {
5557

5658
private final HttpClient client;
5759

60+
private final Map<Integer, SoftReference<HttpClient>> clients = new ConcurrentHashMap<>();
61+
5862
/**
5963
* Creates the new Http2Client using following defaults:
6064
*
@@ -139,16 +143,26 @@ private HttpClient getOrCreateClient(Options options) {
139143
if (doesClientConfigurationDiffer(options)) {
140144
// create a new client from the existing one - but with connectTimeout and followRedirect
141145
// settings from options
142-
java.net.http.HttpClient.Builder builder =
143-
newClientBuilder(options)
144-
.sslContext(client.sslContext())
145-
.sslParameters(client.sslParameters())
146-
.version(client.version());
147-
client.authenticator().ifPresent(builder::authenticator);
148-
client.cookieHandler().ifPresent(builder::cookieHandler);
149-
client.executor().ifPresent(builder::executor);
150-
client.proxy().ifPresent(builder::proxy);
151-
return builder.build();
146+
final int clientKey = createClientKey(options);
147+
148+
SoftReference<HttpClient> requestScopedSoftReference = clients.get(clientKey);
149+
HttpClient requestScoped =
150+
requestScopedSoftReference == null ? null : requestScopedSoftReference.get();
151+
152+
if (requestScoped == null) {
153+
java.net.http.HttpClient.Builder builder =
154+
newClientBuilder(options)
155+
.sslContext(client.sslContext())
156+
.sslParameters(client.sslParameters())
157+
.version(client.version());
158+
client.authenticator().ifPresent(builder::authenticator);
159+
client.cookieHandler().ifPresent(builder::cookieHandler);
160+
client.executor().ifPresent(builder::executor);
161+
client.proxy().ifPresent(builder::proxy);
162+
requestScoped = builder.build();
163+
clients.put(clientKey, new SoftReference<>(requestScoped));
164+
}
165+
return requestScoped;
152166
}
153167
return client;
154168
}
@@ -163,6 +177,24 @@ private boolean doesClientConfigurationDiffer(Options options) {
163177
.orElse(true);
164178
}
165179

180+
/**
181+
* Creates integer key that represents {@link Options} settings based on {@link
182+
* Http2Client#doesClientConfigurationDiffer(Options)} method
183+
*
184+
* @param options value
185+
* @return integer key
186+
*/
187+
public int createClientKey(feign.Request.Options options) {
188+
int key = options.connectTimeoutMillis();
189+
if (options.isFollowRedirects()) {
190+
key |=
191+
1
192+
<< 31; // connectTimeoutMillis always positive, so we can use first sign bit for
193+
// isFollowRedirects flag
194+
}
195+
return key;
196+
}
197+
166198
private static java.net.http.HttpClient.Builder newClientBuilder(Options options) {
167199
return HttpClient.newBuilder()
168200
.followRedirects(options.isFollowRedirects() ? Redirect.ALWAYS : Redirect.NEVER)

0 commit comments

Comments
 (0)