Auto-configure the new Elasticsearch clients
This commit introduces auto-configuration for the new Elasticsearch clients that are based upon their new Java client. The new Java client builds on top of their existing low-level REST client, replacing the high-level REST client which has been deprecated. As part of introducing support for the new Elasticsearch client, the auto-configuration for the templates (both imperative and reactive) provided by Spring Data has also been updated to use the new templates that build upon the new Java client. As part of these changes, support for the high-level REST client and the old Spring Data Elasticsearch templates has been removed. One significant change is that the new reactive template is no longer based on WebClient. As a result, the WebClient-specific configuration property has been removed. Closes gh-30647 Closes gh-28597 Closes gh-31755
This commit is contained in:
parent
f9ccfc1e12
commit
5c057a2730
|
@ -103,7 +103,6 @@ dependencies {
|
|||
optional("org.eclipse.jetty:jetty-server") {
|
||||
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
|
||||
}
|
||||
optional("org.elasticsearch:elasticsearch")
|
||||
optional("org.elasticsearch.client:elasticsearch-rest-client") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
}
|
||||
|
@ -168,9 +167,6 @@ dependencies {
|
|||
testImplementation("org.eclipse.jetty:jetty-webapp") {
|
||||
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
|
||||
}
|
||||
testImplementation("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
||||
exclude(group: "commons-logging", module: "commons-logging")
|
||||
}
|
||||
testImplementation("org.hamcrest:hamcrest")
|
||||
testImplementation("org.hsqldb:hsqldb")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for
|
||||
|
@ -45,7 +45,7 @@ import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearch
|
|||
@ConditionalOnClass({ ReactiveElasticsearchClient.class, Flux.class })
|
||||
@ConditionalOnBean(ReactiveElasticsearchClient.class)
|
||||
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
||||
public class ElasticSearchReactiveHealthContributorAutoConfiguration extends
|
||||
public class ElasticsearchReactiveHealthContributorAutoConfiguration extends
|
||||
CompositeReactiveHealthContributorConfiguration<ElasticsearchReactiveHealthIndicator, ReactiveElasticsearchClient> {
|
||||
|
||||
@Bean
|
|
@ -43,7 +43,7 @@ import org.springframework.context.annotation.Bean;
|
|||
@ConditionalOnClass(RestClient.class)
|
||||
@ConditionalOnBean(RestClient.class)
|
||||
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
||||
public class ElasticSearchRestHealthContributorAutoConfiguration
|
||||
public class ElasticsearchRestHealthContributorAutoConfiguration
|
||||
extends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, RestClient> {
|
||||
|
||||
@Bean
|
|
@ -14,8 +14,8 @@ org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationP
|
|||
org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseReactiveHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticSearchReactiveHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticSearchRestHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticsearchReactiveHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticsearchRestHealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ElasticSearchReactiveHealthContributorAutoConfiguration}.
|
||||
* Tests for {@link ElasticsearchReactiveHealthContributorAutoConfiguration}.
|
||||
*
|
||||
* @author Aleksander Lech
|
||||
*/
|
||||
|
@ -39,7 +39,7 @@ class ElasticsearchReactiveHealthContributorAutoConfigurationTests {
|
|||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchDataAutoConfiguration.class,
|
||||
ReactiveElasticsearchClientAutoConfiguration.class, ElasticsearchRestClientAutoConfiguration.class,
|
||||
ElasticSearchReactiveHealthContributorAutoConfiguration.class,
|
||||
ElasticsearchReactiveHealthContributorAutoConfiguration.class,
|
||||
HealthContributorAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
|
@ -51,7 +51,7 @@ class ElasticsearchReactiveHealthContributorAutoConfigurationTests {
|
|||
@Test
|
||||
void runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {
|
||||
this.contextRunner
|
||||
.withConfiguration(AutoConfigurations.of(ElasticSearchRestHealthContributorAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestHealthContributorAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchReactiveHealthIndicator.class)
|
||||
.hasBean("elasticsearchHealthContributor")
|
||||
.doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class));
|
||||
|
|
|
@ -32,16 +32,16 @@ import org.springframework.context.annotation.Configuration;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ElasticSearchRestHealthContributorAutoConfiguration}.
|
||||
* Tests for {@link ElasticsearchRestHealthContributorAutoConfiguration}.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ElasticSearchRestHealthContributorAutoConfigurationTests {
|
||||
class ElasticsearchRestHealthContributorAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
||||
ElasticSearchRestHealthContributorAutoConfiguration.class,
|
||||
ElasticsearchRestHealthContributorAutoConfiguration.class,
|
||||
HealthContributorAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
|
@ -51,29 +51,19 @@ class ElasticSearchRestHealthContributorAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
void runWithoutRestHighLevelClientAndWithoutRestClientShouldNotCreateIndicator() {
|
||||
this.contextRunner
|
||||
.withClassLoader(
|
||||
new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class, RestClient.class))
|
||||
void runWithoutRestClientShouldNotCreateIndicator() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(RestClient.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)
|
||||
.doesNotHaveBean("elasticsearchHealthContributor"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void runWithoutRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
|
||||
void runWithRestClientShouldCreateIndicator() {
|
||||
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
|
||||
.hasBean("elasticsearchHealthContributor"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void runWithRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
|
||||
this.contextRunner.withUserConfiguration(CustomRestHighClientConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
|
||||
.hasBean("elasticsearchHealthContributor"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void runWhenDisabledShouldNotCreateIndicator() {
|
||||
this.contextRunner.withPropertyValues("management.health.elasticsearch.enabled:false")
|
||||
|
@ -91,20 +81,4 @@ class ElasticSearchRestHealthContributorAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@SuppressWarnings("deprecation")
|
||||
static class CustomRestHighClientConfiguration {
|
||||
|
||||
@Bean
|
||||
org.elasticsearch.client.RestHighLevelClient customRestHighClient(RestClientBuilder builder) {
|
||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
||||
}
|
||||
|
||||
@Bean
|
||||
RestClient customClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
|
||||
return restHighLevelClient.getLowLevelClient();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -43,13 +43,9 @@ dependencies {
|
|||
optional("org.eclipse.jetty:jetty-server") {
|
||||
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
|
||||
}
|
||||
optional("org.elasticsearch:elasticsearch")
|
||||
optional("org.elasticsearch.client:elasticsearch-rest-client") {
|
||||
exclude(group: "commons-logging", module: "commons-logging")
|
||||
}
|
||||
optional("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
||||
exclude(group: "commons-logging", module: "commons-logging")
|
||||
}
|
||||
optional("org.flywaydb:flyway-core")
|
||||
optional("org.hibernate.validator:hibernate-validator")
|
||||
optional("org.influxdb:influxdb-java")
|
||||
|
|
|
@ -16,20 +16,15 @@
|
|||
|
||||
package org.springframework.boot.actuate.elasticsearch;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import co.elastic.clients.elasticsearch._types.HealthStatus;
|
||||
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
|
||||
/**
|
||||
* {@link HealthIndicator} for an Elasticsearch cluster using a
|
||||
|
@ -42,11 +37,6 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||
*/
|
||||
public class ElasticsearchReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
|
||||
|
||||
private static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<>() {
|
||||
};
|
||||
|
||||
private static final String RED_STATUS = "red";
|
||||
|
||||
private final ReactiveElasticsearchClient client;
|
||||
|
||||
public ElasticsearchReactiveHealthIndicator(ReactiveElasticsearchClient client) {
|
||||
|
@ -56,32 +46,33 @@ public class ElasticsearchReactiveHealthIndicator extends AbstractReactiveHealth
|
|||
|
||||
@Override
|
||||
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
||||
return this.client.execute((webClient) -> getHealth(builder, webClient));
|
||||
return this.client.cluster().health((b) -> b).map((response) -> processResponse(builder, response));
|
||||
}
|
||||
|
||||
private Mono<Health> getHealth(Health.Builder builder, WebClient webClient) {
|
||||
return webClient.get().uri("/_cluster/health/").exchangeToMono((response) -> doHealthCheck(builder, response));
|
||||
}
|
||||
|
||||
private Mono<Health> doHealthCheck(Health.Builder builder, ClientResponse response) {
|
||||
HttpStatusCode httpStatusCode = response.statusCode();
|
||||
HttpStatus httpStatus = HttpStatus.resolve(httpStatusCode.value());
|
||||
if (httpStatusCode.is2xxSuccessful()) {
|
||||
return response.bodyToMono(STRING_OBJECT_MAP).map((body) -> getHealth(builder, body));
|
||||
}
|
||||
builder.down();
|
||||
builder.withDetail("statusCode", httpStatusCode.value());
|
||||
if (httpStatus != null) {
|
||||
builder.withDetail("reasonPhrase", httpStatus.getReasonPhrase());
|
||||
}
|
||||
return response.releaseBody().thenReturn(builder.build());
|
||||
}
|
||||
|
||||
private Health getHealth(Health.Builder builder, Map<String, Object> body) {
|
||||
String status = (String) body.get("status");
|
||||
builder.status(RED_STATUS.equals(status) ? Status.OUT_OF_SERVICE : Status.UP);
|
||||
builder.withDetails(body);
|
||||
private Health processResponse(Health.Builder builder, HealthResponse response) {
|
||||
if (!response.timedOut()) {
|
||||
HealthStatus status = response.status();
|
||||
builder.status((HealthStatus.Red == status) ? Status.OUT_OF_SERVICE : Status.UP);
|
||||
builder.withDetail("cluster_name", response.clusterName());
|
||||
builder.withDetail("status", response.status().jsonValue());
|
||||
builder.withDetail("timed_out", response.timedOut());
|
||||
builder.withDetail("number_of_nodes", response.numberOfNodes());
|
||||
builder.withDetail("number_of_data_nodes", response.numberOfDataNodes());
|
||||
builder.withDetail("active_primary_shards", response.activePrimaryShards());
|
||||
builder.withDetail("active_shards", response.activeShards());
|
||||
builder.withDetail("relocating_shards", response.relocatingShards());
|
||||
builder.withDetail("initializing_shards", response.initializingShards());
|
||||
builder.withDetail("unassigned_shards", response.unassignedShards());
|
||||
builder.withDetail("delayed_unassigned_shards", response.delayedUnassignedShards());
|
||||
builder.withDetail("number_of_pending_tasks", response.numberOfPendingTasks());
|
||||
builder.withDetail("number_of_in_flight_fetch", response.numberOfInFlightFetch());
|
||||
builder.withDetail("task_max_waiting_in_queue_millis",
|
||||
response.taskMaxWaitingInQueueMillis().toEpochMilli());
|
||||
builder.withDetail("active_shards_percent_as_number",
|
||||
Double.parseDouble(response.activeShardsPercentAsNumber()));
|
||||
return builder.build();
|
||||
}
|
||||
return builder.down().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,16 +19,20 @@ package org.springframework.boot.actuate.elasticsearch;
|
|||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -50,13 +54,13 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
|||
|
||||
private ElasticsearchReactiveHealthIndicator healthIndicator;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
this.server = new MockWebServer();
|
||||
this.server.start();
|
||||
ReactiveElasticsearchClient client = org.springframework.data.elasticsearch.client.erhlc.DefaultReactiveElasticsearchClient
|
||||
.create(ClientConfiguration.create(this.server.getHostName() + ":" + this.server.getPort()));
|
||||
ReactiveElasticsearchClient client = new ReactiveElasticsearchClient(new RestClientTransport(
|
||||
RestClient.builder(HttpHost.create(this.server.getHostName() + ":" + this.server.getPort())).build(),
|
||||
new JacksonJsonpMapper()));
|
||||
this.healthIndicator = new ElasticsearchReactiveHealthIndicator(client);
|
||||
}
|
||||
|
||||
|
@ -86,20 +90,15 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
|||
this.server.shutdown();
|
||||
Health health = this.healthIndicator.health().block(TIMEOUT);
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(health.getDetails().get("error")).asString()
|
||||
.contains("org.springframework.data.elasticsearch.client.NoReachableHostException");
|
||||
assertThat(health.getDetails().get("error")).asString().contains("Connection refused");
|
||||
}
|
||||
|
||||
@Test
|
||||
void elasticsearchIsDownByResponseCode() {
|
||||
// first enqueue an OK response since the HostChecker first sends a HEAD request
|
||||
// to "/"
|
||||
this.server.enqueue(new MockResponse().setResponseCode(HttpStatus.OK.value()));
|
||||
this.server.enqueue(new MockResponse().setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));
|
||||
Health health = this.healthIndicator.health().block(TIMEOUT);
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(health.getDetails().get("statusCode")).asString().isEqualTo("500");
|
||||
assertThat(health.getDetails().get("reasonPhrase")).asString().isEqualTo("Internal Server Error");
|
||||
assertThat(health.getDetails().get("error")).asString().startsWith(ResponseException.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -116,24 +115,19 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
|||
entry("active_primary_shards", 0), entry("active_shards", 0), entry("relocating_shards", 0),
|
||||
entry("initializing_shards", 0), entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
|
||||
entry("number_of_pending_tasks", 0), entry("number_of_in_flight_fetch", 0),
|
||||
entry("task_max_waiting_in_queue_millis", 0), entry("active_shards_percent_as_number", 100.0));
|
||||
entry("task_max_waiting_in_queue_millis", 0L), entry("active_shards_percent_as_number", 100.0));
|
||||
}
|
||||
|
||||
private void setupMockResponse(int responseCode, String status) {
|
||||
// first enqueue an OK response since the HostChecker first sends a HEAD request
|
||||
// to "/"
|
||||
this.server.enqueue(new MockResponse());
|
||||
MockResponse mockResponse = new MockResponse().setResponseCode(HttpStatus.valueOf(responseCode).value())
|
||||
.setBody(createJsonResult(responseCode, status))
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
MockResponse mockResponse = new MockResponse().setBody(createJsonResult(status))
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setHeader("X-Elastic-Product", "Elasticsearch");
|
||||
this.server.enqueue(mockResponse);
|
||||
}
|
||||
|
||||
private String createJsonResult(int responseCode, String status) {
|
||||
if (responseCode == 200) {
|
||||
private String createJsonResult(String status) {
|
||||
return String.format(
|
||||
"{\"cluster_name\":\"elasticsearch\","
|
||||
+ "\"status\":\"%s\",\"timed_out\":false,\"number_of_nodes\":1,"
|
||||
"{\"cluster_name\":\"elasticsearch\"," + "\"status\":\"%s\",\"timed_out\":false,\"number_of_nodes\":1,"
|
||||
+ "\"number_of_data_nodes\":1,\"active_primary_shards\":0,"
|
||||
+ "\"active_shards\":0,\"relocating_shards\":0,\"initializing_shards\":0,"
|
||||
+ "\"unassigned_shards\":0,\"delayed_unassigned_shards\":0,"
|
||||
|
@ -141,7 +135,5 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
|||
+ "\"task_max_waiting_in_queue_millis\":0,\"active_shards_percent_as_number\":100.0}",
|
||||
status);
|
||||
}
|
||||
return "{\n \"error\": \"Server Error\",\n \"status\": " + responseCode + "\n}";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ description = "Spring Boot AutoConfigure"
|
|||
dependencies {
|
||||
api(project(":spring-boot-project:spring-boot"))
|
||||
|
||||
optional("co.elastic.clients:elasticsearch-java") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
}
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
|
||||
|
@ -99,9 +102,6 @@ dependencies {
|
|||
optional("org.elasticsearch.client:elasticsearch-rest-client-sniffer") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
}
|
||||
optional("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
}
|
||||
optional("org.flywaydb:flyway-core")
|
||||
optional("org.flywaydb:flyway-sqlserver")
|
||||
optional("org.freemarker:freemarker")
|
||||
|
|
|
@ -19,10 +19,10 @@ package org.springframework.boot.autoconfigure.data.elasticsearch;
|
|||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||
|
||||
|
@ -38,12 +38,11 @@ import org.springframework.data.elasticsearch.repository.config.EnableReactiveEl
|
|||
* @see EnableReactiveElasticsearchRepositories
|
||||
*/
|
||||
@AutoConfiguration(
|
||||
after = { ElasticsearchRestClientAutoConfiguration.class, ReactiveElasticsearchClientAutoConfiguration.class })
|
||||
@ConditionalOnClass({ ElasticsearchRestTemplate.class })
|
||||
after = { ElasticsearchClientAutoConfiguration.class, ReactiveElasticsearchClientAutoConfiguration.class })
|
||||
@ConditionalOnClass({ ElasticsearchTemplate.class })
|
||||
@Import({ ElasticsearchDataConfiguration.BaseConfiguration.class,
|
||||
ElasticsearchDataConfiguration.RestClientConfiguration.class,
|
||||
ElasticsearchDataConfiguration.JavaClientConfiguration.class,
|
||||
ElasticsearchDataConfiguration.ReactiveRestClientConfiguration.class })
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ElasticsearchDataAutoConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.data.elasticsearch;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -26,14 +28,15 @@ import org.springframework.context.ApplicationContext;
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
|
||||
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* Configuration classes for Spring Data for Elasticsearch
|
||||
|
@ -77,33 +80,28 @@ abstract class ElasticsearchDataConfiguration {
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
static class RestClientConfiguration {
|
||||
@ConditionalOnClass(ElasticsearchClient.class)
|
||||
static class JavaClientConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ElasticsearchOperations.class, name = "elasticsearchTemplate")
|
||||
@ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchTemplate(
|
||||
org.elasticsearch.client.RestHighLevelClient client, ElasticsearchConverter converter) {
|
||||
return new org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate(client, converter);
|
||||
@ConditionalOnBean(ElasticsearchClient.class)
|
||||
ElasticsearchTemplate elasticsearchTemplate(ElasticsearchClient client, ElasticsearchConverter converter) {
|
||||
return new ElasticsearchTemplate(client, converter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ WebClient.class, ReactiveElasticsearchOperations.class })
|
||||
static class ReactiveRestClientConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ReactiveElasticsearchOperations.class, name = "reactiveElasticsearchTemplate")
|
||||
@ConditionalOnBean(ReactiveElasticsearchClient.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate reactiveElasticsearchTemplate(
|
||||
ReactiveElasticsearchClient client, ElasticsearchConverter converter) {
|
||||
return new org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate(client,
|
||||
converter);
|
||||
ReactiveElasticsearchTemplate reactiveElasticsearchTemplate(ReactiveElasticsearchClient client,
|
||||
ElasticsearchConverter converter) {
|
||||
return new ReactiveElasticsearchTemplate(client, converter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.data.elasticsearch;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
|
@ -38,7 +36,7 @@ import org.springframework.data.elasticsearch.repository.support.ElasticsearchRe
|
|||
* @see EnableElasticsearchRepositories
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass({ Client.class, ElasticsearchRepository.class })
|
||||
@ConditionalOnClass(ElasticsearchRepository.class)
|
||||
@ConditionalOnProperty(prefix = "spring.data.elasticsearch.repositories", name = "enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
@ConditionalOnMissingBean(ElasticsearchRepositoryFactoryBean.class)
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||
import org.springframework.data.elasticsearch.repository.support.ReactiveElasticsearchRepositoryFactoryBean;
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientConfigurations.ElasticsearchClientConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientConfigurations.ElasticsearchTransportConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch's Java client.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@AutoConfiguration(after = { JacksonAutoConfiguration.class, JsonbAutoConfiguration.class,
|
||||
ElasticsearchRestClientAutoConfiguration.class })
|
||||
@ConditionalOnClass(ElasticsearchClient.class)
|
||||
@Import({ ElasticsearchTransportConfiguration.class, ElasticsearchClientConfiguration.class })
|
||||
public class ElasticsearchClientAutoConfiguration {
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.json.SimpleJsonpMapper;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.json.jsonb.JsonbJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.TransportOptions;
|
||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.json.bind.Jsonb;
|
||||
import jakarta.json.spi.JsonProvider;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Configurations for import into {@link ElasticsearchClientAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ElasticsearchClientConfigurations {
|
||||
|
||||
@ConditionalOnMissingBean(JsonpMapper.class)
|
||||
@ConditionalOnBean(ObjectMapper.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JacksonJsonpMapperConfiguration {
|
||||
|
||||
@Bean
|
||||
JacksonJsonpMapper jacksonJsonpMapper(ObjectMapper objectMapper) {
|
||||
return new JacksonJsonpMapper(objectMapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(JsonpMapper.class)
|
||||
@ConditionalOnBean(Jsonb.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JsonbJsonpMapperConfiguration {
|
||||
|
||||
@Bean
|
||||
JsonbJsonpMapper jsonbJsonpMapper(Jsonb jsonb) {
|
||||
return new JsonbJsonpMapper(JsonProvider.provider(), jsonb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(JsonpMapper.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SimpleJsonpMapperConfiguration {
|
||||
|
||||
@Bean
|
||||
SimpleJsonpMapper simpleJsonpMapper() {
|
||||
return new SimpleJsonpMapper();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Import({ JacksonJsonpMapperConfiguration.class, JsonbJsonpMapperConfiguration.class,
|
||||
SimpleJsonpMapperConfiguration.class })
|
||||
@ConditionalOnBean(RestClient.class)
|
||||
@ConditionalOnMissingBean(ElasticsearchTransport.class)
|
||||
static class ElasticsearchTransportConfiguration {
|
||||
|
||||
@Bean
|
||||
RestClientTransport restClientTransport(RestClient restClient, JsonpMapper jsonMapper,
|
||||
ObjectProvider<TransportOptions> transportOptions) {
|
||||
return new RestClientTransport(restClient, jsonMapper, transportOptions.getIfAvailable());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(ElasticsearchTransport.class)
|
||||
static class ElasticsearchClientConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ElasticsearchClient elasticsearchClient(ElasticsearchTransport transport) {
|
||||
return new ElasticsearchClient(transport);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -22,7 +22,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
/**
|
||||
* Configuration properties for Elasticsearch.
|
||||
|
@ -65,8 +64,6 @@ public class ElasticsearchProperties {
|
|||
|
||||
private final Restclient restclient = new Restclient();
|
||||
|
||||
private final Webclient webclient = new Webclient();
|
||||
|
||||
public List<String> getUris() {
|
||||
return this.uris;
|
||||
}
|
||||
|
@ -119,10 +116,6 @@ public class ElasticsearchProperties {
|
|||
return this.restclient;
|
||||
}
|
||||
|
||||
public Webclient getWebclient() {
|
||||
return this.webclient;
|
||||
}
|
||||
|
||||
public static class Restclient {
|
||||
|
||||
private final Sniffer sniffer = new Sniffer();
|
||||
|
@ -163,22 +156,4 @@ public class ElasticsearchProperties {
|
|||
|
||||
}
|
||||
|
||||
public static class Webclient {
|
||||
|
||||
/**
|
||||
* Limit on the number of bytes that can be buffered whenever the input stream
|
||||
* needs to be aggregated.
|
||||
*/
|
||||
private DataSize maxInMemorySize;
|
||||
|
||||
public DataSize getMaxInMemorySize() {
|
||||
return this.maxInMemorySize;
|
||||
}
|
||||
|
||||
public void setMaxInMemorySize(DataSize maxInMemorySize) {
|
||||
this.maxInMemorySize = maxInMemorySize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,9 +23,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientBuilderConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientFromRestHighLevelClientConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientSnifferConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestHighLevelClientConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
|
@ -39,9 +37,7 @@ import org.springframework.context.annotation.Import;
|
|||
@AutoConfiguration
|
||||
@ConditionalOnClass(RestClientBuilder.class)
|
||||
@EnableConfigurationProperties(ElasticsearchProperties.class)
|
||||
@Import({ RestClientBuilderConfiguration.class, RestHighLevelClientConfiguration.class,
|
||||
RestClientFromRestHighLevelClientConfiguration.class, RestClientConfiguration.class,
|
||||
RestClientSnifferConfiguration.class })
|
||||
@Import({ RestClientBuilderConfiguration.class, RestClientConfiguration.class, RestClientSnifferConfiguration.class })
|
||||
public class ElasticsearchRestClientAutoConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import org.elasticsearch.client.sniff.SnifferBuilder;
|
|||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -109,36 +108,7 @@ class ElasticsearchRestClientConfigurations {
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
@ConditionalOnMissingBean({ org.elasticsearch.client.RestHighLevelClient.class, RestClient.class })
|
||||
static class RestHighLevelClientConfiguration {
|
||||
|
||||
@Bean
|
||||
org.elasticsearch.client.RestHighLevelClient elasticsearchRestHighLevelClient(
|
||||
RestClientBuilder restClientBuilder) {
|
||||
return new org.elasticsearch.client.RestHighLevelClient(restClientBuilder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
@ConditionalOnSingleCandidate(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
@ConditionalOnMissingBean(RestClient.class)
|
||||
static class RestClientFromRestHighLevelClientConfiguration {
|
||||
|
||||
@Bean
|
||||
RestClient elasticsearchRestClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
|
||||
return restHighLevelClient.getLowLevelClient();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingClass("org.elasticsearch.client.RestHighLevelClient")
|
||||
@ConditionalOnMissingBean(RestClient.class)
|
||||
static class RestClientConfiguration {
|
||||
|
||||
|
|
|
@ -16,207 +16,37 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchClients;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveRestClients;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch Reactive REST
|
||||
* clients.
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data Elasticsearch's
|
||||
* reactive client.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass({ ReactiveRestClients.class, ElasticsearchException.class, GetIndexRequest.class, WebClient.class,
|
||||
HttpClient.class })
|
||||
@AutoConfiguration(after = ElasticsearchClientAutoConfiguration.class)
|
||||
@ConditionalOnClass({ ReactiveElasticsearchClient.class, ElasticsearchTransport.class, Mono.class })
|
||||
@EnableConfigurationProperties(ElasticsearchProperties.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
@Import(ElasticsearchClientConfigurations.ElasticsearchTransportConfiguration.class)
|
||||
public class ReactiveElasticsearchClientAutoConfiguration {
|
||||
|
||||
private final ConsolidatedProperties properties;
|
||||
|
||||
ReactiveElasticsearchClientAutoConfiguration(ElasticsearchProperties properties) {
|
||||
this.properties = new ConsolidatedProperties(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ClientConfiguration clientConfiguration() {
|
||||
ClientConfiguration.MaybeSecureClientConfigurationBuilder builder = ClientConfiguration.builder()
|
||||
.connectedTo(this.properties.getEndpoints().toArray(new String[0]));
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(this.properties.isUseSsl()).whenTrue().toCall(builder::usingSsl);
|
||||
map.from(this.properties.getCredentials())
|
||||
.to((credentials) -> builder.withBasicAuth(credentials.getUsername(), credentials.getPassword()));
|
||||
map.from(this.properties.getConnectionTimeout()).to(builder::withConnectTimeout);
|
||||
map.from(this.properties.getSocketTimeout()).to(builder::withSocketTimeout);
|
||||
map.from(this.properties.getPathPrefix()).to(builder::withPathPrefix);
|
||||
configureExchangeStrategies(map, builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void configureExchangeStrategies(PropertyMapper map,
|
||||
ClientConfiguration.TerminalClientConfigurationBuilder builder) {
|
||||
map.from(this.properties.getMaxInMemorySize()).asInt(DataSize::toBytes).to((maxInMemorySize) -> {
|
||||
builder.withClientConfigurer(ElasticsearchClients.WebClientConfigurationCallback.from((webClient) -> {
|
||||
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
|
||||
.codecs((configurer) -> configurer.defaultCodecs().maxInMemorySize(maxInMemorySize)).build();
|
||||
return webClient.mutate().exchangeStrategies(exchangeStrategies).build();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ReactiveElasticsearchClient reactiveElasticsearchClient(ClientConfiguration clientConfiguration) {
|
||||
return ReactiveRestClients.create(clientConfiguration);
|
||||
}
|
||||
|
||||
private static final class ConsolidatedProperties {
|
||||
|
||||
private final ElasticsearchProperties properties;
|
||||
|
||||
private final List<URI> uris;
|
||||
|
||||
private ConsolidatedProperties(ElasticsearchProperties properties) {
|
||||
this.properties = properties;
|
||||
this.uris = properties.getUris().stream().map((s) -> s.startsWith("http") ? s : "http://" + s)
|
||||
.map(URI::create).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<String> getEndpoints() {
|
||||
return this.uris.stream().map(this::getEndpoint).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String getEndpoint(URI uri) {
|
||||
return uri.getHost() + ":" + uri.getPort();
|
||||
}
|
||||
|
||||
private Credentials getCredentials() {
|
||||
Credentials propertyCredentials = Credentials.from(this.properties);
|
||||
Credentials uriCredentials = Credentials.from(this.uris);
|
||||
if (uriCredentials == null) {
|
||||
return propertyCredentials;
|
||||
}
|
||||
Assert.isTrue(propertyCredentials == null || uriCredentials.equals(propertyCredentials),
|
||||
"Credentials from URI user info do not match those from spring.elasticsearch.username and "
|
||||
+ "spring.elasticsearch.password");
|
||||
return uriCredentials;
|
||||
}
|
||||
|
||||
private Duration getConnectionTimeout() {
|
||||
return this.properties.getConnectionTimeout();
|
||||
}
|
||||
|
||||
private Duration getSocketTimeout() {
|
||||
return this.properties.getSocketTimeout();
|
||||
}
|
||||
|
||||
private boolean isUseSsl() {
|
||||
Set<String> schemes = this.uris.stream().map(URI::getScheme).collect(Collectors.toSet());
|
||||
Assert.isTrue(schemes.size() == 1, "Configured Elasticsearch URIs have varying schemes");
|
||||
return schemes.iterator().next().equals("https");
|
||||
}
|
||||
|
||||
private DataSize getMaxInMemorySize() {
|
||||
return this.properties.getWebclient().getMaxInMemorySize();
|
||||
}
|
||||
|
||||
private String getPathPrefix() {
|
||||
return this.properties.getPathPrefix();
|
||||
}
|
||||
|
||||
private static final class Credentials {
|
||||
|
||||
private final String username;
|
||||
|
||||
private final String password;
|
||||
|
||||
private Credentials(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
private String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
private static Credentials from(List<URI> uris) {
|
||||
Set<String> userInfos = uris.stream().map(URI::getUserInfo).collect(Collectors.toSet());
|
||||
Assert.isTrue(userInfos.size() == 1, "Configured Elasticsearch URIs have varying user infos");
|
||||
String userInfo = userInfos.iterator().next();
|
||||
if (userInfo == null) {
|
||||
return null;
|
||||
}
|
||||
String[] parts = userInfo.split(":");
|
||||
String username = parts[0];
|
||||
String password = (parts.length != 2) ? "" : parts[1];
|
||||
return new Credentials(username, password);
|
||||
}
|
||||
|
||||
private static Credentials from(ElasticsearchProperties properties) {
|
||||
return getCredentials(properties.getUsername(), properties.getPassword());
|
||||
}
|
||||
|
||||
private static Credentials getCredentials(String username, String password) {
|
||||
if (username == null && password == null) {
|
||||
return null;
|
||||
}
|
||||
return new Credentials(username, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Credentials other = (Credentials) obj;
|
||||
return ObjectUtils.nullSafeEquals(this.username, other.username)
|
||||
&& ObjectUtils.nullSafeEquals(this.password, other.password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.username);
|
||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.password);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnBean(ElasticsearchTransport.class)
|
||||
ReactiveElasticsearchClient reactiveElasticsearchClient(ElasticsearchTransport transport) {
|
||||
return new ReactiveElasticsearchClient(transport);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -981,6 +981,15 @@
|
|||
"http://localhost:9200"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "spring.elasticsearch.webclient.max-in-memory-size",
|
||||
"type": "org.springframework.util.unit.DataSize",
|
||||
"description": "Limit on the number of bytes that can be buffered whenever the input stream needs to be aggregated.",
|
||||
"deprecation": {
|
||||
"level": "error",
|
||||
"reason": "Reactive Elasticsearch client no longer uses WebClient."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.flyway.baseline-migration-prefix",
|
||||
"defaultValue": "B"
|
||||
|
|
|
@ -39,6 +39,7 @@ org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration
|
|||
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
|
||||
|
|
|
@ -20,21 +20,20 @@ import java.math.BigDecimal;
|
|||
import java.util.Collections;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
|
@ -53,26 +52,16 @@ import static org.mockito.Mockito.mock;
|
|||
* @author Scott Frederick
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class ElasticsearchDataAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
||||
ReactiveElasticsearchClientAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class));
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
System.clearProperty("es.set.netty.runtime.available.processors");
|
||||
}
|
||||
ElasticsearchClientAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
|
||||
ReactiveElasticsearchClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void defaultRestBeansRegistered() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestTemplate.class)
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class)
|
||||
.hasSingleBean(ReactiveElasticsearchTemplate.class).hasSingleBean(ElasticsearchConverter.class)
|
||||
.hasSingleBean(ElasticsearchConverter.class).hasSingleBean(ElasticsearchCustomConversions.class));
|
||||
}
|
||||
|
@ -92,19 +81,19 @@ class ElasticsearchDataAutoConfigurationTests {
|
|||
this.contextRunner.withUserConfiguration(CustomElasticsearchCustomConversions.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(ElasticsearchCustomConversions.class).hasBean("testCustomConversions");
|
||||
assertThat(context.getBean(ElasticsearchConverter.class).getConversionService()
|
||||
.canConvert(ElasticsearchRestTemplate.class, Boolean.class)).isTrue();
|
||||
.canConvert(ElasticsearchTemplate.class, Boolean.class)).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customRestTemplateShouldBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomRestTemplate.class).run((context) -> assertThat(context)
|
||||
.getBeanNames(ElasticsearchRestTemplate.class).hasSize(1).contains("elasticsearchTemplate"));
|
||||
.getBeanNames(ElasticsearchTemplate.class).hasSize(1).contains("elasticsearchTemplate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void customReactiveRestTemplateShouldBeUsed() {
|
||||
this.contextRunner.withUserConfiguration(CustomReactiveRestTemplate.class)
|
||||
this.contextRunner.withUserConfiguration(CustomReactiveElasticsearchTemplate.class)
|
||||
.run((context) -> assertThat(context).getBeanNames(ReactiveElasticsearchTemplate.class).hasSize(1)
|
||||
.contains("reactiveElasticsearchTemplate"));
|
||||
}
|
||||
|
@ -131,14 +120,14 @@ class ElasticsearchDataAutoConfigurationTests {
|
|||
static class CustomRestTemplate {
|
||||
|
||||
@Bean
|
||||
ElasticsearchRestTemplate elasticsearchTemplate() {
|
||||
return mock(ElasticsearchRestTemplate.class);
|
||||
ElasticsearchTemplate elasticsearchTemplate() {
|
||||
return mock(ElasticsearchTemplate.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomReactiveRestTemplate {
|
||||
static class CustomReactiveElasticsearchTemplate {
|
||||
|
||||
@Bean
|
||||
ReactiveElasticsearchTemplate reactiveElasticsearchTemplate() {
|
||||
|
@ -153,10 +142,10 @@ class ElasticsearchDataAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
static class MyConverter implements Converter<ElasticsearchRestTemplate, Boolean> {
|
||||
static class MyConverter implements Converter<ElasticsearchTemplate, Boolean> {
|
||||
|
||||
@Override
|
||||
public Boolean convert(ElasticsearchRestTemplate source) {
|
||||
public Boolean convert(ElasticsearchTemplate source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,11 +29,12 @@ import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityElastic
|
|||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.CityRepository;
|
||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -46,7 +47,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Brian Clozel
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
@SuppressWarnings("deprecation")
|
||||
class ElasticsearchRepositoriesAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
|
@ -55,19 +55,20 @@ class ElasticsearchRepositoriesAutoConfigurationTests {
|
|||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
||||
ElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class))
|
||||
ElasticsearchClientAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class,
|
||||
ElasticsearchDataAutoConfiguration.class))
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress());
|
||||
|
||||
@Test
|
||||
void testDefaultRepositoryConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> assertThat(context)
|
||||
.hasSingleBean(CityRepository.class).hasSingleBean(ElasticsearchRestTemplate.class));
|
||||
.hasSingleBean(CityRepository.class).hasSingleBean(ElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoRepositoryConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestTemplate.class));
|
||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -29,11 +29,12 @@ import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityReactiv
|
|||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.ReactiveCityRepository;
|
||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -46,7 +47,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Brian Clozel
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
@SuppressWarnings("deprecation")
|
||||
class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
|
||||
|
||||
@Container
|
||||
|
@ -54,7 +54,8 @@ class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
|
|||
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveElasticsearchClientAutoConfiguration.class,
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class,
|
||||
ElasticsearchRestClientAutoConfiguration.class,
|
||||
ReactiveElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.elasticsearch.uris=" + elasticsearch.getHost() + ":" + elasticsearch.getFirstMappedPort(),
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link ElasticsearchClientAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ElasticsearchClientAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static ElasticsearchContainer elasticsearch = new ElasticsearchContainer(DockerImageNames.elasticsearch())
|
||||
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,
|
||||
ElasticsearchRestClientAutoConfiguration.class, ElasticsearchClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void reactiveClientCanQueryElasticsearchNode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||
.run((context) -> {
|
||||
ElasticsearchClient client = context.getBean(ElasticsearchClient.class);
|
||||
client.index((b) -> b.index("foo").id("1").document(Map.of("a", "alpha", "b", "bravo")));
|
||||
GetResponse<Object> response = client.get((b) -> b.index("foo").id("1"), Object.class);
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.found()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.json.SimpleJsonpMapper;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.json.jsonb.JsonbJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ElasticsearchClientAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ElasticsearchClientAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void withoutRestClientThenAutoConfigurationShouldBackOff() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchTransport.class)
|
||||
.doesNotHaveBean(JsonpMapper.class).doesNotHaveBean(ElasticsearchClient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withRestClientAutoConfigurationShouldDefineClientAndSupportingBeans() {
|
||||
this.contextRunner.withUserConfiguration(RestClientConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)
|
||||
.hasSingleBean(RestClientTransport.class).hasSingleBean(ElasticsearchClient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withoutJsonbOrJacksonShouldDefineSimpleMapper() {
|
||||
this.contextRunner.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||
.hasSingleBean(JsonpMapper.class).hasSingleBean(SimpleJsonpMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withJsonbShouldDefineJsonbMapper() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class))
|
||||
.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||
.hasSingleBean(JsonpMapper.class).hasSingleBean(JsonbJsonpMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withJacksonShouldDefineJacksonMapper() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
|
||||
.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||
.hasSingleBean(JsonpMapper.class).hasSingleBean(JacksonJsonpMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withJacksonAndJsonbShouldDefineJacksonMapper() {
|
||||
this.contextRunner
|
||||
.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class, JacksonAutoConfiguration.class))
|
||||
.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||
.hasSingleBean(JsonpMapper.class).hasSingleBean(JacksonJsonpMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCustomMapperTransportShouldUseIt() {
|
||||
this.contextRunner.withUserConfiguration(JsonpMapperConfiguration.class)
|
||||
.withUserConfiguration(RestClientConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(JsonpMapper.class).hasBean("customJsonpMapper");
|
||||
JsonpMapper mapper = context.getBean(JsonpMapper.class);
|
||||
assertThat(context.getBean(ElasticsearchTransport.class).jsonpMapper()).isSameAs(mapper);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCustomTransportClientShouldUseIt() {
|
||||
this.contextRunner.withUserConfiguration(TransportConfiguration.class)
|
||||
.withUserConfiguration(RestClientConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(ElasticsearchTransport.class)
|
||||
.hasBean("customElasticsearchTransport");
|
||||
ElasticsearchTransport transport = context.getBean(ElasticsearchTransport.class);
|
||||
assertThat(context.getBean(ElasticsearchClient.class)._transport()).isSameAs(transport);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class RestClientConfiguration {
|
||||
|
||||
@Bean
|
||||
RestClient restClient() {
|
||||
return mock(RestClient.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class JsonpMapperConfiguration {
|
||||
|
||||
@Bean
|
||||
JsonpMapper customJsonpMapper() {
|
||||
return mock(JsonpMapper.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TransportConfiguration {
|
||||
|
||||
@Bean
|
||||
ElasticsearchTransport customElasticsearchTransport() {
|
||||
return mock(ElasticsearchTransport.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -18,15 +18,10 @@ package org.springframework.boot.autoconfigure.elasticsearch;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -58,25 +53,6 @@ class ElasticsearchRestClientAutoConfigurationIntegrationTests {
|
|||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
void restHighLevelClientCanQueryElasticsearchNode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||
.run((context) -> {
|
||||
org.elasticsearch.client.RestHighLevelClient client = context
|
||||
.getBean(org.elasticsearch.client.RestHighLevelClient.class);
|
||||
Map<String, String> source = new HashMap<>();
|
||||
source.put("a", "alpha");
|
||||
source.put("b", "bravo");
|
||||
IndexRequest index = new IndexRequest("test").id("1").source(source);
|
||||
client.index(index, RequestOptions.DEFAULT);
|
||||
GetRequest getRequest = new GetRequest("test").id("1");
|
||||
assertThat(client.get(getRequest, RequestOptions.DEFAULT).isExists()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void restClientCanQueryElasticsearchNode() {
|
||||
this.contextRunner
|
||||
|
|
|
@ -50,74 +50,32 @@ import static org.mockito.Mockito.mock;
|
|||
* @author Filip Hrisafov
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
class ElasticsearchRestClientAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void configureShouldCreateHighLevelAndLowLevelRestClients() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(RestClient.class)
|
||||
.hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
.hasSingleBean(RestClientBuilder.class);
|
||||
assertThat(context.getBean(RestClient.class))
|
||||
.isEqualTo(context.getBean(org.elasticsearch.client.RestHighLevelClient.class).getLowLevelClient());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithoutRestHighLevelClientShouldOnlyCreateRestClientBuilderAndRestClient() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(RestClient.class)
|
||||
.hasSingleBean(RestClientBuilder.class)
|
||||
.doesNotHaveBean(org.elasticsearch.client.RestHighLevelClient.class));
|
||||
void configureShouldCreateRestClientBuilderAndRestClient() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(RestClient.class)
|
||||
.hasSingleBean(RestClientBuilder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenCustomRestClientShouldBackOff() {
|
||||
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
.hasSingleBean(RestClientBuilder.class).hasSingleBean(RestClient.class)
|
||||
.hasBean("customRestClient"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenCustomRestHighLevelClientShouldDefineRestClientFromCustomHighLevelClient() {
|
||||
this.contextRunner.withUserConfiguration(CustomRestHighLevelClientConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
.hasSingleBean(RestClient.class).hasBean("elasticsearchRestClient").getBean(RestClient.class)
|
||||
.isEqualTo(context.getBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
.getLowLevelClient()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenCustomRestHighLevelClientAndRestClientShouldBackOff() {
|
||||
this.contextRunner.withUserConfiguration(CustomRestHighLevelClientWithRestClientConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
.hasBean("customRestHighLevelClient").hasSingleBean(RestClient.class)
|
||||
.hasBean("customRestClient"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenNoUniqueRestHighLevelClientShouldNotDefineRestClient() {
|
||||
this.contextRunner.withUserConfiguration(TwoCustomRestHighLevelClientsConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(RestClient.class));
|
||||
.run((context) -> assertThat(context).hasSingleBean(RestClientBuilder.class)
|
||||
.hasSingleBean(RestClient.class).hasBean("customRestClient"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenBuilderCustomizerShouldApply() {
|
||||
this.contextRunner.withUserConfiguration(BuilderCustomizerConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
.hasSingleBean(RestClient.class);
|
||||
org.elasticsearch.client.RestHighLevelClient restClient = context
|
||||
.getBean(org.elasticsearch.client.RestHighLevelClient.class);
|
||||
RestClient lowLevelClient = restClient.getLowLevelClient();
|
||||
assertThat(lowLevelClient).hasFieldOrPropertyWithValue("pathPrefix", "/test");
|
||||
assertThat(lowLevelClient).extracting("client.connmgr.pool.maxTotal").isEqualTo(100);
|
||||
assertThat(lowLevelClient).extracting("client.defaultConfig.cookieSpec").isEqualTo("rfc6265-lax");
|
||||
assertThat(context).hasSingleBean(RestClient.class);
|
||||
RestClient restClient = context.getBean(RestClient.class);
|
||||
assertThat(restClient).hasFieldOrPropertyWithValue("pathPrefix", "/test");
|
||||
assertThat(restClient).extracting("client.connmgr.pool.maxTotal").isEqualTo(100);
|
||||
assertThat(restClient).extracting("client.defaultConfig.cookieSpec").isEqualTo("rfc6265-lax");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -228,14 +186,12 @@ class ElasticsearchRestClientAutoConfigurationTests {
|
|||
@Test
|
||||
void configureWithoutSnifferLibraryShouldNotCreateSniffer() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.elasticsearch.client.sniff"))
|
||||
.run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
||||
.hasSingleBean(RestClient.class).doesNotHaveBean(Sniffer.class));
|
||||
.run((context) -> assertThat(context).hasSingleBean(RestClient.class).doesNotHaveBean(Sniffer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureShouldCreateSnifferUsingRestClient() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class))
|
||||
.run((context) -> {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(Sniffer.class);
|
||||
assertThat(context.getBean(Sniffer.class)).hasFieldOrPropertyWithValue("restClient",
|
||||
context.getBean(RestClient.class));
|
||||
|
@ -297,46 +253,6 @@ class ElasticsearchRestClientAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomRestHighLevelClientConfiguration {
|
||||
|
||||
@Bean
|
||||
org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClientBuilder builder) {
|
||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomRestHighLevelClientWithRestClientConfiguration {
|
||||
|
||||
@Bean
|
||||
org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClientBuilder builder) {
|
||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
||||
}
|
||||
|
||||
@Bean
|
||||
RestClient customRestClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
|
||||
return restHighLevelClient.getLowLevelClient();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TwoCustomRestHighLevelClientsConfiguration {
|
||||
|
||||
@Bean
|
||||
org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClientBuilder builder) {
|
||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
||||
}
|
||||
|
||||
@Bean
|
||||
org.elasticsearch.client.RestHighLevelClient anotherCustomRestHighLevelClient(RestClientBuilder builder) {
|
||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomRestClientConfiguration {
|
||||
|
||||
|
|
|
@ -17,21 +17,21 @@
|
|||
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.index.get.GetResult;
|
||||
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||
import co.elastic.clients.elasticsearch.core.IndexResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -39,32 +39,33 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* Integration tests for {@link ReactiveElasticsearchClientAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class ReactiveElasticsearchRestClientAutoConfigurationIntegrationTests {
|
||||
class ReactiveElasticsearchClientAutoConfigurationIntegrationTests {
|
||||
|
||||
@Container
|
||||
static ElasticsearchContainer elasticsearch = new ElasticsearchContainer(DockerImageNames.elasticsearch())
|
||||
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactiveElasticsearchClientAutoConfiguration.class));
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(JacksonAutoConfiguration.class, ElasticsearchRestClientAutoConfiguration.class,
|
||||
ReactiveElasticsearchClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void restClientCanQueryElasticsearchNode() {
|
||||
void reactiveClientCanQueryElasticsearchNode() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||
.run((context) -> {
|
||||
ReactiveElasticsearchClient client = context.getBean(ReactiveElasticsearchClient.class);
|
||||
Map<String, String> source = new HashMap<>();
|
||||
source.put("a", "alpha");
|
||||
source.put("b", "bravo");
|
||||
IndexRequest indexRequest = new IndexRequest("foo").id("1").source(source);
|
||||
GetRequest getRequest = new GetRequest("foo").id("1");
|
||||
GetResult getResult = client.index(indexRequest).then(client.get(getRequest)).block();
|
||||
assertThat(getResult).isNotNull();
|
||||
assertThat(getResult.isExists()).isTrue();
|
||||
Mono<IndexResponse> index = client
|
||||
.index((b) -> b.index("foo").id("1").document(Map.of("a", "alpha", "b", "bravo")));
|
||||
index.block();
|
||||
Mono<GetResponse<Object>> get = client.get((b) -> b.index("foo").id("1"), Object.class);
|
||||
GetResponse<Object> response = get.block();
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.found()).isTrue();
|
||||
});
|
||||
}
|
||||
|
|
@ -16,25 +16,14 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
||||
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.codec.CodecConfigurer.DefaultCodecConfig;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -43,6 +32,7 @@ import static org.mockito.Mockito.mock;
|
|||
* Tests for {@link ReactiveElasticsearchClientAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ReactiveElasticsearchClientAutoConfigurationTests {
|
||||
|
||||
|
@ -50,206 +40,31 @@ class ReactiveElasticsearchClientAutoConfigurationTests {
|
|||
.withConfiguration(AutoConfigurations.of(ReactiveElasticsearchClientAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void configureShouldCreateDefaultBeans() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ClientConfiguration.class)
|
||||
.hasSingleBean(ReactiveElasticsearchClient.class);
|
||||
List<InetSocketAddress> endpoints = context.getBean(ClientConfiguration.class).getEndpoints();
|
||||
assertThat(endpoints).hasSize(1);
|
||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9200);
|
||||
});
|
||||
void configureWithoutRestClientShouldBackOff() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveElasticsearchClient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithRestClientShouldCreateTransportAndClient() {
|
||||
this.contextRunner.withUserConfiguration(RestClientConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchClient.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenCustomClientShouldBackOff() {
|
||||
this.contextRunner.withUserConfiguration(CustomClientConfiguration.class).run((context) -> assertThat(context)
|
||||
.hasSingleBean(ReactiveElasticsearchClient.class).hasBean("customClient"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWhenCustomClientConfig() {
|
||||
this.contextRunner.withUserConfiguration(CustomClientConfigConfiguration.class)
|
||||
this.contextRunner.withUserConfiguration(RestClientConfiguration.class, CustomClientConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchClient.class)
|
||||
.hasSingleBean(ClientConfiguration.class).hasBean("customClientConfiguration"));
|
||||
.hasBean("customClient"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUriIsCustomizedThenClientConfigurationHasCustomEndpoint() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://localhost:9876").run((context) -> {
|
||||
List<InetSocketAddress> endpoints = context.getBean(ClientConfiguration.class).getEndpoints();
|
||||
assertThat(endpoints).hasSize(1);
|
||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
||||
});
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class RestClientConfiguration {
|
||||
|
||||
@Bean
|
||||
RestClient restClient() {
|
||||
return mock(RestClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUriHasHttpsSchemeThenClientConfigurationUsesSsl() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=https://localhost:9876").run((context) -> {
|
||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
||||
List<InetSocketAddress> endpoints = clientConfiguration.getEndpoints();
|
||||
assertThat(endpoints).hasSize(1);
|
||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
||||
assertThat(clientConfiguration.useSsl()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMultipleUrisAreConfiguredThenClientConfigurationHasMultipleEndpoints() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://localhost:9876,http://localhost:8765")
|
||||
.run((context) -> {
|
||||
List<InetSocketAddress> endpoints = context.getBean(ClientConfiguration.class).getEndpoints();
|
||||
assertThat(endpoints).hasSize(2);
|
||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
||||
assertThat(endpoints.get(1).getHostString()).isEqualTo("localhost");
|
||||
assertThat(endpoints.get(1).getPort()).isEqualTo(8765);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMultipleUrisHaveHttpsSchemeThenClientConfigurationUsesSsl() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=https://localhost:9876,https://localhost:8765")
|
||||
.run((context) -> {
|
||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
||||
List<InetSocketAddress> endpoints = clientConfiguration.getEndpoints();
|
||||
assertThat(endpoints).hasSize(2);
|
||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
||||
assertThat(endpoints.get(1).getHostString()).isEqualTo("localhost");
|
||||
assertThat(endpoints.get(1).getPort()).isEqualTo(8765);
|
||||
assertThat(clientConfiguration.useSsl()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMultipleUrisHaveVaryingSchemesThenRunFails() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=https://localhost:9876,http://localhost:8765")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().hasRootCauseInstanceOf(IllegalArgumentException.class)
|
||||
.hasRootCauseMessage("Configured Elasticsearch URIs have varying schemes");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUriHasUsernameOnlyThenDefaultAuthorizationHeaderHasUsernameAndEmptyPassword() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user@localhost:9200").run((context) -> {
|
||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
||||
assertThat(clientConfiguration.getDefaultHeaders().get(HttpHeaders.AUTHORIZATION)).containsExactly(
|
||||
"Basic " + Base64.getEncoder().encodeToString("user:".getBytes(StandardCharsets.UTF_8)));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUriHasUsernameAndPasswordThenDefaultAuthorizationHeaderHasUsernameAndPassword() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9200")
|
||||
.run((context) -> {
|
||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
||||
assertThat(clientConfiguration.getDefaultHeaders().get(HttpHeaders.AUTHORIZATION))
|
||||
.containsExactly("Basic " + Base64.getEncoder()
|
||||
.encodeToString("user:secret".getBytes(StandardCharsets.UTF_8)));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMultipleUrisHaveVaryingUserInfosThenRunFails() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9876,http://localhost:8765")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().hasRootCauseInstanceOf(IllegalArgumentException.class)
|
||||
.hasRootCauseMessage("Configured Elasticsearch URIs have varying user infos");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUriUserInfoMatchesUsernameAndPasswordPropertiesThenDefaultAuthorizationHeaderIsConfigured() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9876",
|
||||
"spring.elasticsearch.username=user", "spring.elasticsearch.password=secret").run((context) -> {
|
||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
||||
assertThat(clientConfiguration.getDefaultHeaders().get(HttpHeaders.AUTHORIZATION))
|
||||
.containsExactly("Basic " + Base64.getEncoder()
|
||||
.encodeToString("user:secret".getBytes(StandardCharsets.UTF_8)));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUriUserInfoAndUsernameAndPasswordPropertiesDoNotMatchThenRunFails() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9876",
|
||||
"spring.elasticsearch.username=alice", "spring.elasticsearch.password=confidential")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context).getFailure().hasRootCauseInstanceOf(IllegalArgumentException.class)
|
||||
.hasRootCauseMessage("Credentials from URI user info do not match those from "
|
||||
+ "spring.elasticsearch.username and spring.elasticsearch.password");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenSocketTimeoutIsNotConfiguredThenClientConfigurationUsesDefault() {
|
||||
this.contextRunner.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getSocketTimeout())
|
||||
.isEqualTo(Duration.ofSeconds(30)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConnectionTimeoutIsNotConfiguredThenClientConfigurationUsesDefault() {
|
||||
this.contextRunner.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getConnectTimeout())
|
||||
.isEqualTo(Duration.ofSeconds(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenSocketTimeoutIsConfiguredThenClientConfigurationHasCustomSocketTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.socket-timeout=2s")
|
||||
.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getSocketTimeout())
|
||||
.isEqualTo(Duration.ofSeconds(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConnectionTimeoutIsConfiguredThenClientConfigurationHasCustomConnectTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.connection-timeout=2s")
|
||||
.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getConnectTimeout())
|
||||
.isEqualTo(Duration.ofSeconds(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenPathPrefixIsConfiguredThenClientConfigurationHasPathPrefix() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.path-prefix=/some/prefix")
|
||||
.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getPathPrefix())
|
||||
.isEqualTo("/some/prefix"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCredentialsAreConfiguredThenClientConfigurationHasDefaultAuthorizationHeader() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.elasticsearch.username=alice", "spring.elasticsearch.password=secret")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ClientConfiguration.class).getDefaultHeaders().get(HttpHeaders.AUTHORIZATION))
|
||||
.containsExactly("Basic YWxpY2U6c2VjcmV0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenMaxInMemorySizeIsConfiguredThenUnderlyingWebClientHasCustomMaxInMemorySize() {
|
||||
this.contextRunner.withPropertyValues("spring.elasticsearch.webclient.max-in-memory-size=1MB")
|
||||
.run((context) -> {
|
||||
WebClient client = configureWebClient(
|
||||
context.getBean(ClientConfiguration.class).getClientConfigurers());
|
||||
assertThat(client).extracting("exchangeFunction.strategies.codecConfigurer.defaultCodecs")
|
||||
.asInstanceOf(InstanceOfAssertFactories.type(DefaultCodecConfig.class))
|
||||
.extracting(DefaultCodecConfig::maxInMemorySize).isEqualTo(1024 * 1024);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private WebClient configureWebClient(List<ClientConfigurationCallback<?>> callbacks) {
|
||||
WebClient webClient = WebClient.create();
|
||||
for (ClientConfigurationCallback<?> callback : callbacks) {
|
||||
webClient = ((ClientConfiguration.ClientConfigurationCallback<WebClient>) callback).configure(webClient);
|
||||
}
|
||||
return webClient;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
@ -262,14 +77,4 @@ class ReactiveElasticsearchClientAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomClientConfigConfiguration {
|
||||
|
||||
@Bean
|
||||
ClientConfiguration customClientConfiguration() {
|
||||
return ClientConfiguration.localhost();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.springframework.http.converter.StringHttpMessageConverter;
|
|||
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
|
||||
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
||||
|
@ -58,8 +57,7 @@ class HttpMessageConvertersTests {
|
|||
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
|
||||
ResourceRegionHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
||||
AllEncompassingFormHttpMessageConverter.class, MappingJackson2HttpMessageConverter.class,
|
||||
MappingJackson2SmileHttpMessageConverter.class, MappingJackson2CborHttpMessageConverter.class,
|
||||
MappingJackson2XmlHttpMessageConverter.class);
|
||||
MappingJackson2CborHttpMessageConverter.class, MappingJackson2XmlHttpMessageConverter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -130,7 +128,7 @@ class HttpMessageConvertersTests {
|
|||
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
|
||||
ResourceRegionHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
||||
AllEncompassingFormHttpMessageConverter.class, MappingJackson2HttpMessageConverter.class,
|
||||
MappingJackson2SmileHttpMessageConverter.class, MappingJackson2CborHttpMessageConverter.class);
|
||||
MappingJackson2CborHttpMessageConverter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -151,7 +149,7 @@ class HttpMessageConvertersTests {
|
|||
}
|
||||
assertThat(converterClasses).containsExactly(ByteArrayHttpMessageConverter.class,
|
||||
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
||||
MappingJackson2HttpMessageConverter.class, MappingJackson2SmileHttpMessageConverter.class);
|
||||
MappingJackson2HttpMessageConverter.class);
|
||||
}
|
||||
|
||||
private List<HttpMessageConverter<?>> extractFormPartConverters(List<HttpMessageConverter<?>> converters) {
|
||||
|
|
|
@ -212,34 +212,20 @@ bom {
|
|||
]
|
||||
}
|
||||
}
|
||||
library("Elasticsearch", "7.17.5") {
|
||||
group("org.elasticsearch") {
|
||||
modules = [
|
||||
"elasticsearch"
|
||||
]
|
||||
}
|
||||
library("Elasticsearch Client", "8.3.2") {
|
||||
group("org.elasticsearch.client") {
|
||||
modules = [
|
||||
"transport",
|
||||
"elasticsearch-rest-client" {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
},
|
||||
"elasticsearch-rest-client-sniffer" {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
},
|
||||
"elasticsearch-rest-high-level-client"
|
||||
]
|
||||
}
|
||||
group("org.elasticsearch.distribution.integ-test-zip") {
|
||||
group("co.elastic.clients") {
|
||||
modules = [
|
||||
"elasticsearch" {
|
||||
type = 'zip'
|
||||
}
|
||||
]
|
||||
}
|
||||
group("org.elasticsearch.plugin") {
|
||||
modules = [
|
||||
"transport-netty4-client"
|
||||
"elasticsearch-java"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -999,3 +999,6 @@ dependency-versions.properties=appendix.dependency-versions.properties
|
|||
|
||||
# gh-30405
|
||||
web.servlet.spring-mvc.json=features.json.jackson.custom-serializers-and-deserializers
|
||||
|
||||
# gh-28597
|
||||
data.nosql.elasticsearch.connecting-using-rest.webclient=data.nosql.elasticsearch.connecting-using-rest.reactiveclient
|
||||
|
|
|
@ -203,7 +203,8 @@ Spring Boot offers basic auto-configuration for Elasticsearch clients.
|
|||
|
||||
Spring Boot supports several clients:
|
||||
|
||||
* The official Java "Low Level" and "High Level" REST clients
|
||||
* The official low-level REST client
|
||||
* The official Java API client
|
||||
* The `ReactiveElasticsearchClient` provided by Spring Data Elasticsearch
|
||||
|
||||
Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elasticsearch`.
|
||||
|
@ -212,8 +213,8 @@ Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elastics
|
|||
|
||||
[[data.nosql.elasticsearch.connecting-using-rest]]
|
||||
==== Connecting to Elasticsearch using REST clients
|
||||
Elasticsearch ships https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html[two different REST clients] that you can use to query a cluster: the low-level client from the `org.elasticsearch.client:elasticsearch-rest-client` module and the high-level client from the `org.elasticsearch.client:elasticsearch-high-level-client` module.
|
||||
Additionally, Spring Boot provides support for a reactive client, based on Spring Framework's `WebClient`, from the `org.springframework.data:spring-data-elasticsearch` module.
|
||||
Elasticsearch ships two different REST clients] that you can use to query a cluster: the https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/java-rest-low.html[low-level client] from the `org.elasticsearch.client:elasticsearch-rest-client` module and the https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html[Java API client] from the `co.elastic.clients:elasticsearch-java` module.
|
||||
Additionally, Spring Boot provides support for a reactive client from the `org.springframework.data:spring-data-elasticsearch` module.
|
||||
By default, the clients will target `http://localhost:9200`.
|
||||
You can use `spring.elasticsearch.*` properties to further tune how the clients are configured, as shown in the following example:
|
||||
|
||||
|
@ -230,9 +231,7 @@ You can use `spring.elasticsearch.*` properties to further tune how the clients
|
|||
[[data.nosql.elasticsearch.connecting-using-rest.restclient]]
|
||||
===== Connecting to Elasticsearch using RestClient
|
||||
If you have `elasticsearch-rest-client` on the classpath, Spring Boot will auto-configure and register a `RestClient` bean.
|
||||
If you have `elasticsearch-rest-high-level-client` on the classpath a `RestHighLevelClient` bean will be auto-configured as well.
|
||||
Following Elasticsearch's deprecation of `RestHighLevelClient`, its auto-configuration is deprecated and will be removed in a future release.
|
||||
In addition to the properties described previously, to fine-tune the `RestClient` and `RestHighLevelClient`, you can register an arbitrary number of beans that implement `RestClientBuilderCustomizer` for more advanced customizations.
|
||||
In addition to the properties described previously, to fine-tune the `RestClient` you can register an arbitrary number of beans that implement `RestClientBuilderCustomizer` for more advanced customizations.
|
||||
To take full control over the clients' configuration, define a `RestClientBuilder` bean.
|
||||
|
||||
|
||||
|
@ -251,38 +250,38 @@ You can further tune how `Sniffer` is configured, as shown in the following exam
|
|||
----
|
||||
|
||||
|
||||
[[data.nosql.elasticsearch.connecting-using-rest.javaapiclient]]
|
||||
===== Connecting to Elastixsearch using ElasticsearchClient
|
||||
If you have `co.elastic.clients:elasticsearch-java` on the classpath, Spring Boot will auto-configure and register an `ElasticsearchClient` bean.
|
||||
|
||||
[[data.nosql.elasticsearch.connecting-using-rest.webclient]]
|
||||
The `ElasticsearchClient` uses a transport that depends upon the previously described `RestClient`.
|
||||
Therefore, the properties described previously can be used to configure the `ElasticsearchClient`.
|
||||
Furthermore, you can define a `TransportOptions` bean to take further control of the behavior of the transport.
|
||||
|
||||
|
||||
|
||||
[[data.nosql.elasticsearch.connecting-using-rest.reactiveclient]]
|
||||
===== Connecting to Elasticsearch using ReactiveElasticsearchClient
|
||||
{spring-data-elasticsearch}[Spring Data Elasticsearch] ships `ReactiveElasticsearchClient` for querying Elasticsearch instances in a reactive fashion.
|
||||
It is built on top of WebFlux's `WebClient`, so both `spring-boot-starter-elasticsearch` and `spring-boot-starter-webflux` dependencies are useful to enable this support.
|
||||
If you have Spring Data Elasticsearch and Reactor on the classpath, Spring Boot will auto-configure and register a `ReactiveElasticsearchClient`.
|
||||
|
||||
By default, Spring Boot will auto-configure and register a `ReactiveElasticsearchClient`.
|
||||
In addition to the properties described previously, the `spring.elasticsearch.webclient.*` properties can be used to configure reactive-specific settings, as shown in the following example:
|
||||
|
||||
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
|
||||
----
|
||||
spring:
|
||||
elasticsearch:
|
||||
webclient:
|
||||
max-in-memory-size: "1MB"
|
||||
----
|
||||
|
||||
If the `spring.elasticsearch.*` and `spring.elasticsearch.webclient.*` configuration properties are not enough and you'd like to fully control the client configuration, you can register a custom `ClientConfiguration` bean.
|
||||
The `ReactiveElasticsearchclient` uses a transport that depends upon the previously described `RestClient`.
|
||||
Therefore, the properties described previously can be used to configure the `ReactiveElasticsearchClient`.
|
||||
Furthermore, you can define a `TransportOptions` bean to take further control of the behavior of the transport.
|
||||
|
||||
|
||||
|
||||
[[data.nosql.elasticsearch.connecting-using-spring-data]]
|
||||
==== Connecting to Elasticsearch by Using Spring Data
|
||||
To connect to Elasticsearch, a `RestHighLevelClient` bean must be defined,
|
||||
To connect to Elasticsearch, an `ElasticsearchClient` bean must be defined,
|
||||
auto-configured by Spring Boot or manually provided by the application (see previous sections).
|
||||
With this configuration in place, an
|
||||
`ElasticsearchRestTemplate` can be injected like any other Spring bean,
|
||||
`ElasticsearchTemplate` can be injected like any other Spring bean,
|
||||
as shown in the following example:
|
||||
|
||||
include::code:MyBean[]
|
||||
|
||||
In the presence of `spring-data-elasticsearch` and the required dependencies for using a `WebClient` (typically `spring-boot-starter-webflux`), Spring Boot can also auto-configure a <<features#data.nosql.elasticsearch.connecting-using-rest.webclient,ReactiveElasticsearchClient>> and a `ReactiveElasticsearchTemplate` as beans.
|
||||
In the presence of `spring-data-elasticsearch` and Reactor, Spring Boot can also auto-configure a <<features#data.nosql.elasticsearch.connecting-using-rest.reactiveclient,ReactiveElasticsearchClient>> and a `ReactiveElasticsearchTemplate` as beans.
|
||||
They are the reactive equivalent of the other REST clients.
|
||||
|
||||
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
|
||||
package org.springframework.boot.docs.data.nosql.elasticsearch.connectingusingspringdata;
|
||||
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MyBean {
|
||||
|
||||
private final org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate template;
|
||||
private final ElasticsearchTemplate template;
|
||||
|
||||
public MyBean(org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate template) {
|
||||
public MyBean(ElasticsearchTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,11 +101,6 @@ dependencies {
|
|||
testImplementation("org.testcontainers:neo4j")
|
||||
testImplementation("org.testcontainers:testcontainers")
|
||||
testImplementation("org.thymeleaf:thymeleaf")
|
||||
|
||||
testRuntimeOnly("org.elasticsearch:elasticsearch")
|
||||
testRuntimeOnly("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
||||
exclude group: "commons-logging", module: "commons-logging"
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
|
||||
|
@ -53,8 +54,7 @@ class DataElasticsearchTestIntegrationTests {
|
|||
}
|
||||
|
||||
@Autowired
|
||||
@SuppressWarnings("deprecation")
|
||||
private org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchRestTemplate;
|
||||
private ElasticsearchTemplate elasticsearchTemplate;
|
||||
|
||||
@Autowired
|
||||
private ExampleRepository exampleRepository;
|
||||
|
@ -75,7 +75,7 @@ class DataElasticsearchTestIntegrationTests {
|
|||
String id = UUID.randomUUID().toString();
|
||||
document.setId(id);
|
||||
ExampleDocument savedDocument = this.exampleRepository.save(document);
|
||||
ExampleDocument getDocument = this.elasticsearchRestTemplate.get(id, ExampleDocument.class);
|
||||
ExampleDocument getDocument = this.elasticsearchTemplate.get(id, ExampleDocument.class);
|
||||
assertThat(getDocument).isNotNull();
|
||||
assertThat(getDocument.getId()).isNotNull();
|
||||
assertThat(getDocument.getId()).isEqualTo(savedDocument.getId());
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
|||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
|
||||
|
@ -50,8 +51,7 @@ class DataElasticsearchTestReactiveIntegrationTests {
|
|||
}
|
||||
|
||||
@Autowired
|
||||
@SuppressWarnings("deprecation")
|
||||
private org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate elasticsearchTemplate;
|
||||
private ReactiveElasticsearchTemplate elasticsearchTemplate;
|
||||
|
||||
@Autowired
|
||||
private ExampleReactiveRepository exampleReactiveRepository;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.test.autoconfigure.data.elasticsearch;
|
||||
|
||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
|
@ -24,18 +25,16 @@ import org.springframework.stereotype.Service;
|
|||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Service
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ExampleService {
|
||||
|
||||
private final org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchRestTemplate;
|
||||
private final ElasticsearchTemplate elasticsearchTemplate;
|
||||
|
||||
public ExampleService(
|
||||
org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchRestTemplate) {
|
||||
this.elasticsearchRestTemplate = elasticsearchRestTemplate;
|
||||
public ExampleService(ElasticsearchTemplate elasticsearchRestTemplate) {
|
||||
this.elasticsearchTemplate = elasticsearchRestTemplate;
|
||||
}
|
||||
|
||||
public ExampleDocument findById(String id) {
|
||||
return this.elasticsearchRestTemplate.get(id, ExampleDocument.class);
|
||||
return this.elasticsearchTemplate.get(id, ExampleDocument.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ dependencies {
|
|||
}
|
||||
compileOnly("jakarta.servlet:jakarta.servlet-api")
|
||||
compileOnly("junit:junit")
|
||||
compileOnly("org.elasticsearch:elasticsearch")
|
||||
compileOnly("org.junit.jupiter:junit-jupiter")
|
||||
compileOnly("org.junit.platform:junit-platform-engine")
|
||||
compileOnly("org.junit.platform:junit-platform-launcher")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -30,6 +30,8 @@ public final class DockerImageNames {
|
|||
|
||||
private static final String COUCHBASE_VERSION = "6.5.1";
|
||||
|
||||
private static final String ELASTICSEARCH_VERSION = "7.17.5";
|
||||
|
||||
private static final String MONGO_VERSION = "4.0.23";
|
||||
|
||||
private static final String NEO4J_VERSION = "4.0";
|
||||
|
@ -60,13 +62,11 @@ public final class DockerImageNames {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return a {@link DockerImageName} suitable for running Elasticsearch according to
|
||||
* the version available on the classpath.
|
||||
* Return a {@link DockerImageName} suitable for running Elasticsearch.
|
||||
* @return a docker image name for running elasticsearch
|
||||
*/
|
||||
public static DockerImageName elasticsearch() {
|
||||
String version = org.elasticsearch.Version.CURRENT.toString();
|
||||
return DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch").withTag(version);
|
||||
return DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch").withTag(ELASTICSEARCH_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue