Refine the configuration callbacks in the ClientConfiguration.

Original Pull Request #2237
Closes #2149
This commit is contained in:
Peter-Josef Meisch 2022-07-23 15:32:24 +02:00 committed by GitHub
parent 373be49f97
commit 1c31a31e11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 42 deletions

View File

@ -38,16 +38,17 @@ ElasticsearchClient elasticsearchClient; <.>
@Autowired
RestClient restClient; <.>
----
the following can be injected:
<.> an implementation of `ElasticsearchOperations`
<.> the `co.elastic.clients.elasticsearch.ElasticsearchClient` that is used. This is new Elasticsearch client
implementation.
<.> an implementation of `ElasticsearchOperations`
<.> the `co.elastic.clients.elasticsearch.ElasticsearchClient` that is used.
This is new Elasticsearch client implementation.
<.> the low level `RestClient` from the Elasticsearch libraries
====
Basically one should just use the `ElasticsearchOperations` to interact with the Elasticsearch cluster. When using
repositories, this instance is used under the hood as well.
Basically one should just use the `ElasticsearchOperations` to interact with the Elasticsearch cluster.
When using repositories, this instance is used under the hood as well.
[[elasticsearch.clients.reactiverestclient]]
== Reactive Rest Client
@ -81,21 +82,22 @@ ReactiveElasticsearchClient elasticsearchClient; <.>
@Autowired
RestClient restClient; <.>
----
the following can be injected:
<.> an implementation of `ElasticsearchOperations`
<.> the `org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient` that is used. This is based
on the new Elasticsearch client implementation.
<.> the `org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient` that is used.
This is based on the new Elasticsearch client implementation.
<.> the low level `RestClient` from the Elasticsearch libraries
====
Basically one should just use the `ReactiveElasticsearchOperations` to interact with the Elasticsearch cluster. When
using repositories, this instance is used under the hood as well.
Basically one should just use the `ReactiveElasticsearchOperations` to interact with the Elasticsearch cluster.
When using repositories, this instance is used under the hood as well.
[[elasticsearch.clients.resthighlevelclient]]
== High Level REST Client (deprecated)
The Java RestHighLevelClient is deprecated, but still can be configured like shown (read
The Java RestHighLevelClient is deprecated, but still can be configured like shown (read
<<elasticsearch-migration-guide-4.4-5.0.old-client>> as well):
.RestHighLevelClient
@ -231,12 +233,49 @@ Default is 5 sec.
<.> Optionally set headers.
<.> Add basic authentication.
<.> A `Supplier<Header>` function can be specified which is called every time before a request is sent to Elasticsearch - here, as an example, the current time is written in a header.
<.> a function configuring the low level REST client (the same for the imperative and reactive stack)
<.> a function to configure the created client (see <<elasticsearch.clients.configuration.callbacks>>), can be added multiple times.
====
IMPORTANT: Adding a Header supplier as shown in above example allows to inject headers that may change over the time, like authentication JWT tokens.
If this is used in the reactive setup, the supplier function *must not* block!
[[elasticsearch.clients.configuration.callbacks]]
=== Client configuration callbacks
The `ClientConfiguration` class offers the most common parameters to configure the client. In the case this is not
enough, the user can add callback functions by using the `withClientConfigurer(ClientConfigurationCallback<?>)` method.
The following callbacks are provided:
==== Configuration of the low level Elasticsearch `RestClient`:
====
[source,java]
----
ClientConfiguration.builder()
.withClientConfigurer(ElasticsearchClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
// configure the Elasticsearch RestClient
return restClientBuilder;
}))
.build();
----
====
==== Configuration of the HttpAsyncClient used by the low level Elasticsearch `RestClient`:
====
[source,java]
----
ClientConfiguration.builder()
.withClientConfigurer(ElasticsearchClients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
// configure the HttpAsyncClient
return httpAsyncClientBuilder;
}))
.build();
----
====
=== Elasticsearch 7 compatibility headers
When using the deprecated `RestHighLevelClient` and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers

View File

@ -36,7 +36,7 @@ If you are using `ElasticsearchRestTemplate` directly and not the `Elasticsearch
adjust your imports as well.
When working with the `NativeSearchQuery` class, you'll need to switch to the `NativeQuery` class, which can take a
`Query` instance comign from the new Elasticsearch client libraries. You'll find plenty of examples in the test code.
`Query` instance comign from the new Elasticsearch client libraries. You'll find plenty of examples in the test code.
[[elasticsearch-migration-guide-4.4-5.0.new-clients]]
== New Elasticsearch client

View File

@ -56,7 +56,6 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.client.WebClient;
/**
* Utility class to create the different Elasticsearch clients
@ -229,14 +228,20 @@ public final class ElasticsearchClients {
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurer instanceof ElasticsearchClientConfigurationCallback) {
ElasticsearchClientConfigurationCallback restClientConfigurationCallback = (ElasticsearchClientConfigurationCallback) clientConfigurer;
if (clientConfigurer instanceof ElasticsearchHttpClientConfigurationCallback restClientConfigurationCallback) {
clientBuilder = restClientConfigurationCallback.configure(clientBuilder);
}
}
return clientBuilder;
});
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurationCallback : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurationCallback instanceof ElasticsearchRestClientConfigurationCallback configurationCallback) {
builder = configurationCallback.configure(builder);
}
}
return builder;
}
@ -360,37 +365,39 @@ public final class ElasticsearchClients {
/**
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
* the RestClient with a {@link HttpAsyncClientBuilder}
* the Elasticsearch RestClient's Http client with a {@link HttpAsyncClientBuilder}
*
* @since 4.4
*/
public interface ElasticsearchClientConfigurationCallback
public interface ElasticsearchHttpClientConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<HttpAsyncClientBuilder> {
static ElasticsearchClientConfigurationCallback from(
Function<HttpAsyncClientBuilder, HttpAsyncClientBuilder> clientBuilderCallback) {
static ElasticsearchHttpClientConfigurationCallback from(
Function<HttpAsyncClientBuilder, HttpAsyncClientBuilder> httpClientBuilderCallback) {
Assert.notNull(clientBuilderCallback, "clientBuilderCallback must not be null");
Assert.notNull(httpClientBuilderCallback, "httpClientBuilderCallback must not be null");
// noinspection NullableProblems
return clientBuilderCallback::apply;
return httpClientBuilderCallback::apply;
}
}
/**
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
* the ReactiveElasticsearchClient with a {@link WebClient}
* the RestClient client with a {@link RestClientBuilder}
*
* @since 4.4
* @since 5.0
*/
public interface WebClientConfigurationCallback extends ClientConfiguration.ClientConfigurationCallback<WebClient> {
public interface ElasticsearchRestClientConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<RestClientBuilder> {
static WebClientConfigurationCallback from(Function<WebClient, WebClient> webClientCallback) {
static ElasticsearchRestClientConfigurationCallback from(
Function<RestClientBuilder, RestClientBuilder> restClientBuilderCallback) {
Assert.notNull(webClientCallback, "webClientCallback must not be null");
Assert.notNull(restClientBuilderCallback, "restClientBuilderCallback must not be null");
// noinspection NullableProblems
return webClientCallback::apply;
return restClientBuilderCallback::apply;
}
}
}

View File

@ -72,7 +72,9 @@ public final class ReactiveRestClients {
* the ReactiveElasticsearchClient with a {@link WebClient}
*
* @since 4.3
* @deprecated
*/
@Deprecated
public interface WebClientConfigurationCallback extends ClientConfiguration.ClientConfigurationCallback<WebClient> {
static WebClientConfigurationCallback from(Function<WebClient, WebClient> webClientCallback) {

View File

@ -252,7 +252,9 @@ public final class RestClients {
* the RestClient with a {@link HttpAsyncClientBuilder}
*
* @since 4.3
* @deprecated since 5.0
*/
@Deprecated
public interface RestClientConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<HttpAsyncClientBuilder> {

View File

@ -35,7 +35,6 @@ import java.util.function.Function;
import javax.net.ssl.SSLContext;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchClients;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
@ -240,11 +239,6 @@ public interface WebClientProvider {
ReactiveRestClients.WebClientConfigurationCallback webClientConfigurationCallback = (ReactiveRestClients.WebClientConfigurationCallback) clientConfigurer;
webClient = webClientConfigurationCallback.configure(webClient);
}
if (clientConfigurer instanceof ElasticsearchClients.WebClientConfigurationCallback) {
ElasticsearchClients.WebClientConfigurationCallback webClientConfigurationCallback = (ElasticsearchClients.WebClientConfigurationCallback) clientConfigurer;
webClient = webClientConfigurationCallback.configure(webClient);
}
}
return webClient;
};

View File

@ -103,7 +103,8 @@ public class RestClientsTest {
defaultHeaders.add("def2", "def2-1");
AtomicInteger supplierCount = new AtomicInteger(1);
AtomicInteger clientConfigurerCount = new AtomicInteger(0);
AtomicInteger httpClientConfigurerCount = new AtomicInteger(0);
AtomicInteger restClientConfigurerCount = new AtomicInteger(0);
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
configurationBuilder //
@ -120,26 +121,36 @@ public class RestClientsTest {
if (clientUnderTestFactory instanceof ERHLCUnderTestFactory) {
configurationBuilder
.withClientConfigurer(RestClients.RestClientConfigurationCallback.from(httpClientBuilder -> {
clientConfigurerCount.incrementAndGet();
httpClientConfigurerCount.incrementAndGet();
return httpClientBuilder;
}));
} else if (clientUnderTestFactory instanceof ReactiveERHLCUnderTestFactory) {
configurationBuilder.withClientConfigurer(ReactiveRestClients.WebClientConfigurationCallback.from(webClient -> {
clientConfigurerCount.incrementAndGet();
httpClientConfigurerCount.incrementAndGet();
return webClient;
}));
} else if (clientUnderTestFactory instanceof ELCUnderTestFactory) {
configurationBuilder.withClientConfigurer(
ElasticsearchClients.ElasticsearchClientConfigurationCallback.from(httpClientBuilder -> {
clientConfigurerCount.incrementAndGet();
ElasticsearchClients.ElasticsearchHttpClientConfigurationCallback.from(httpClientBuilder -> {
httpClientConfigurerCount.incrementAndGet();
return httpClientBuilder;
}));
configurationBuilder.withClientConfigurer(
ElasticsearchClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
restClientConfigurerCount.incrementAndGet();
return restClientBuilder;
}));
} else if (clientUnderTestFactory instanceof ReactiveELCUnderTestFactory) {
configurationBuilder
.withClientConfigurer(ElasticsearchClients.ElasticsearchClientConfigurationCallback.from(webClient -> {
clientConfigurerCount.incrementAndGet();
.withClientConfigurer(ElasticsearchClients.ElasticsearchHttpClientConfigurationCallback.from(webClient -> {
httpClientConfigurerCount.incrementAndGet();
return webClient;
}));
configurationBuilder.withClientConfigurer(
ElasticsearchClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
restClientConfigurerCount.incrementAndGet();
return restClientBuilder;
}));
}
ClientConfiguration clientConfiguration = configurationBuilder.build();
@ -162,7 +173,8 @@ public class RestClientsTest {
);
}
assertThat(clientConfigurerCount).hasValue(1);
assertThat(httpClientConfigurerCount).hasValue(1);
assertThat(restClientConfigurerCount).hasValue(clientUnderTestFactory.getExpectedRestClientConfigCalls());
});
}
@ -328,11 +340,16 @@ public class RestClientsTest {
}
protected abstract String getDisplayName();
protected Integer getExpectedRestClientConfigCalls() {
return 0;
}
}
/**
* {@link ClientUnderTestFactory} implementation for the old {@link RestHighLevelClient}.
*/
@Deprecated
static class ERHLCUnderTestFactory extends ClientUnderTestFactory {
@Override
@ -363,7 +380,6 @@ public class RestClientsTest {
}
};
}
}
/**
@ -376,6 +392,11 @@ public class RestClientsTest {
return "ElasticsearchClient";
}
@Override
protected Integer getExpectedRestClientConfigCalls() {
return 1;
}
@Override
ClientUnderTest create(ClientConfiguration clientConfiguration) {
@ -403,6 +424,7 @@ public class RestClientsTest {
* {@link ClientUnderTestFactory} implementation for the
* {@link org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient}.
*/
@Deprecated
static class ReactiveERHLCUnderTestFactory extends ClientUnderTestFactory {
@Override
@ -446,6 +468,11 @@ public class RestClientsTest {
return "ReactiveElasticsearchClient (ELC based)";
}
@Override
protected Integer getExpectedRestClientConfigCalls() {
return 1;
}
@Override
ClientUnderTest create(ClientConfiguration clientConfiguration) {