diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java index c69b9b0e43c..5713554ad56 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.elasticsearch; import java.util.Map; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; @@ -41,16 +42,16 @@ import org.springframework.context.annotation.Configuration; * @since 2.1.1 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass(RestClient.class) -@ConditionalOnBean(RestClient.class) +@ConditionalOnClass(RestHighLevelClient.class) +@ConditionalOnBean(RestHighLevelClient.class) @ConditionalOnEnabledHealthIndicator("elasticsearch") @AutoConfigureAfter(ElasticsearchRestClientAutoConfiguration.class) public class ElasticSearchRestHealthContributorAutoConfiguration - extends CompositeHealthContributorConfiguration { + extends CompositeHealthContributorConfiguration { @Bean @ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) - public HealthContributor elasticsearchHealthContributor(Map clients) { + public HealthContributor elasticsearchHealthContributor(Map clients) { return createContributor(clients); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java index 79626acd320..c6b7f69332c 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -25,6 +25,7 @@ import org.apache.http.StatusLine; import org.elasticsearch.client.Request; import org.elasticsearch.client.Response; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -49,6 +50,10 @@ public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator { private final JsonParser jsonParser; + public ElasticsearchRestHealthIndicator(RestHighLevelClient client) { + this(client.getLowLevelClient()); + } + public ElasticsearchRestHealthIndicator(RestClient client) { super("Elasticsearch health check failed"); this.client = client; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java index 69d03e23e42..b77922f4a82 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java @@ -16,13 +16,30 @@ package org.springframework.boot.autoconfigure.elasticsearch; +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Duration; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 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.context.annotation.Configuration; -import org.springframework.context.annotation.Import; +import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch REST clients. @@ -32,11 +49,141 @@ import org.springframework.context.annotation.Import; * @since 2.1.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass(RestClient.class) +@ConditionalOnClass(RestHighLevelClient.class) @EnableConfigurationProperties(ElasticsearchRestClientProperties.class) -@Import({ ElasticsearchRestClientConfigurations.RestClientBuilderConfiguration.class, - ElasticsearchRestClientConfigurations.RestHighLevelClientConfiguration.class, - ElasticsearchRestClientConfigurations.RestClientFallbackConfiguration.class }) public class ElasticsearchRestClientAutoConfiguration { + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingBean(RestClientBuilder.class) + static class RestClientBuilderConfiguration { + + @Bean + RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) { + return new DefaultRestClientBuilderCustomizer(properties); + } + + @Bean + RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties, + ObjectProvider builderCustomizers) { + HttpHost[] hosts = properties.getUris().stream().map(this::createHttpHost).toArray(HttpHost[]::new); + RestClientBuilder builder = RestClient.builder(hosts); + builder.setHttpClientConfigCallback((httpClientBuilder) -> { + builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder)); + return httpClientBuilder; + }); + builder.setRequestConfigCallback((requestConfigBuilder) -> { + builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(requestConfigBuilder)); + return requestConfigBuilder; + }); + builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + return builder; + } + + private HttpHost createHttpHost(String uri) { + try { + return createHttpHost(URI.create(uri)); + } + catch (IllegalArgumentException ex) { + return HttpHost.create(uri); + } + } + + private HttpHost createHttpHost(URI uri) { + if (!StringUtils.hasLength(uri.getUserInfo())) { + return HttpHost.create(uri.toString()); + } + try { + return HttpHost.create(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), + uri.getQuery(), uri.getFragment()).toString()); + } + catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingBean(RestHighLevelClient.class) + static class RestHighLevelClientConfiguration { + + @Bean + RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) { + return new RestHighLevelClient(restClientBuilder); + } + + } + + static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCustomizer { + + private static final PropertyMapper map = PropertyMapper.get(); + + private final ElasticsearchRestClientProperties properties; + + DefaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) { + this.properties = properties; + } + + @Override + public void customize(RestClientBuilder builder) { + } + + @Override + public void customize(HttpAsyncClientBuilder builder) { + builder.setDefaultCredentialsProvider(new PropertiesCredentialsProvider(this.properties)); + } + + @Override + public void customize(RequestConfig.Builder builder) { + map.from(this.properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis) + .to(builder::setConnectTimeout); + map.from(this.properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis) + .to(builder::setSocketTimeout); + } + + } + + private static class PropertiesCredentialsProvider extends BasicCredentialsProvider { + + PropertiesCredentialsProvider(ElasticsearchRestClientProperties properties) { + if (StringUtils.hasText(properties.getUsername())) { + Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(), + properties.getPassword()); + setCredentials(AuthScope.ANY, credentials); + } + properties.getUris().stream().map(this::toUri).filter(this::hasUserInfo) + .forEach(this::addUserInfoCredentials); + } + + private URI toUri(String uri) { + try { + return URI.create(uri); + } + catch (IllegalArgumentException ex) { + return null; + } + } + + private boolean hasUserInfo(URI uri) { + return uri != null && StringUtils.hasLength(uri.getUserInfo()); + } + + private void addUserInfoCredentials(URI uri) { + AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort()); + Credentials credentials = createUserInfoCredentials(uri.getUserInfo()); + setCredentials(authScope, credentials); + } + + private Credentials createUserInfoCredentials(String userInfo) { + int delimiter = userInfo.indexOf(":"); + if (delimiter == -1) { + return new UsernamePasswordCredentials(userInfo, null); + } + String username = userInfo.substring(0, delimiter); + String password = userInfo.substring(delimiter + 1); + return new UsernamePasswordCredentials(username, password); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java deleted file mode 100644 index b7ab5e9c0b2..00000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2012-2020 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.net.URI; -import java.net.URISyntaxException; -import java.time.Duration; - -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.elasticsearch.client.RestHighLevelClient; - -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.PropertyMapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.StringUtils; - -/** - * Elasticsearch rest client infrastructure configurations. - * - * @author Brian Clozel - * @author Stephane Nicoll - * @author Vedran Pavic - * @author Evgeniy Cheban - */ -class ElasticsearchRestClientConfigurations { - - @Configuration(proxyBeanMethods = false) - @ConditionalOnMissingBean(RestClientBuilder.class) - static class RestClientBuilderConfiguration { - - @Bean - RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) { - return new DefaultRestClientBuilderCustomizer(properties); - } - - @Bean - RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties, - ObjectProvider builderCustomizers) { - HttpHost[] hosts = properties.getUris().stream().map(this::createHttpHost).toArray(HttpHost[]::new); - RestClientBuilder builder = RestClient.builder(hosts); - builder.setHttpClientConfigCallback((httpClientBuilder) -> { - builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder)); - return httpClientBuilder; - }); - builder.setRequestConfigCallback((requestConfigBuilder) -> { - builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(requestConfigBuilder)); - return requestConfigBuilder; - }); - builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); - return builder; - } - - private HttpHost createHttpHost(String uri) { - try { - return createHttpHost(URI.create(uri)); - } - catch (IllegalArgumentException ex) { - return HttpHost.create(uri); - } - } - - private HttpHost createHttpHost(URI uri) { - if (!StringUtils.hasLength(uri.getUserInfo())) { - return HttpHost.create(uri.toString()); - } - try { - return HttpHost.create(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), - uri.getQuery(), uri.getFragment()).toString()); - } - catch (URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } - - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(RestHighLevelClient.class) - static class RestHighLevelClientConfiguration { - - @Bean - @ConditionalOnMissingBean - RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) { - return new RestHighLevelClient(restClientBuilder); - } - - @Bean - @ConditionalOnMissingBean - RestClient elasticsearchRestClient(RestClientBuilder builder, - ObjectProvider restHighLevelClient) { - RestHighLevelClient client = restHighLevelClient.getIfUnique(); - if (client != null) { - return client.getLowLevelClient(); - } - return builder.build(); - } - - } - - @Configuration(proxyBeanMethods = false) - static class RestClientFallbackConfiguration { - - @Bean - @ConditionalOnMissingBean - RestClient elasticsearchRestClient(RestClientBuilder builder) { - return builder.build(); - } - - } - - static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCustomizer { - - private static final PropertyMapper map = PropertyMapper.get(); - - private final ElasticsearchRestClientProperties properties; - - DefaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) { - this.properties = properties; - } - - @Override - public void customize(RestClientBuilder builder) { - } - - @Override - public void customize(HttpAsyncClientBuilder builder) { - builder.setDefaultCredentialsProvider(new PropertiesCredentialsProvider(this.properties)); - } - - @Override - public void customize(RequestConfig.Builder builder) { - map.from(this.properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis) - .to(builder::setConnectTimeout); - map.from(this.properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis) - .to(builder::setSocketTimeout); - } - - } - - private static class PropertiesCredentialsProvider extends BasicCredentialsProvider { - - PropertiesCredentialsProvider(ElasticsearchRestClientProperties properties) { - if (StringUtils.hasText(properties.getUsername())) { - Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(), - properties.getPassword()); - setCredentials(AuthScope.ANY, credentials); - } - properties.getUris().stream().map(this::toUri).filter(this::hasUserInfo) - .forEach(this::addUserInfoCredentials); - } - - private URI toUri(String uri) { - try { - return URI.create(uri); - } - catch (IllegalArgumentException ex) { - return null; - } - } - - private boolean hasUserInfo(URI uri) { - return uri != null && StringUtils.hasLength(uri.getUserInfo()); - } - - private void addUserInfoCredentials(URI uri) { - AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort()); - Credentials credentials = createUserInfoCredentials(uri.getUserInfo()); - setCredentials(authScope, credentials); - } - - private Credentials createUserInfoCredentials(String userInfo) { - int delimiter = userInfo.indexOf(":"); - if (delimiter == -1) { - return new UsernamePasswordCredentials(userInfo, null); - } - String username = userInfo.substring(0, delimiter); - String password = userInfo.substring(delimiter + 1); - return new UsernamePasswordCredentials(username, password); - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java index 09648bf9bc5..3acf36d1319 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java @@ -40,13 +40,11 @@ import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.FilteredClassLoader; 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 ElasticsearchRestClientAutoConfiguration}. @@ -66,57 +64,34 @@ class ElasticsearchRestClientAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class)); @Test - void configureShouldCreateBothRestClientVariants() { - this.contextRunner.run((context) -> { - assertThat(context).hasSingleBean(RestClient.class).hasSingleBean(RestHighLevelClient.class); - assertThat(context.getBean(RestClient.class)) - .isSameAs(context.getBean(RestHighLevelClient.class).getLowLevelClient()); - }); - } - - @Test - void configureWhenCustomClientShouldBackOff() { - this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class) - .run((context) -> assertThat(context).getBeanNames(RestClient.class).containsOnly("customRestClient")); + void configureShouldOnlyCreateHighLevelRestClient() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(RestClient.class) + .hasSingleBean(RestHighLevelClient.class)); } @Test void configureWhenCustomRestHighLevelClientShouldBackOff() { - this.contextRunner.withUserConfiguration(CustomRestHighLevelClientConfiguration.class).run((context) -> { - assertThat(context).hasSingleBean(RestClient.class).hasSingleBean(RestHighLevelClient.class); - assertThat(context.getBean(RestClient.class)) - .isSameAs(context.getBean(RestHighLevelClient.class).getLowLevelClient()); - }); + this.contextRunner.withUserConfiguration(CustomRestHighLevelClientConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(RestHighLevelClient.class)); } @Test void configureWhenDefaultRestClientShouldCreateWhenNoUniqueRestHighLevelClient() { this.contextRunner.withUserConfiguration(TwoCustomRestHighLevelClientConfiguration.class).run((context) -> { - assertThat(context).hasSingleBean(RestClient.class); - RestClient restClient = context.getBean(RestClient.class); Map restHighLevelClients = context.getBeansOfType(RestHighLevelClient.class); assertThat(restHighLevelClients).hasSize(2); - for (RestHighLevelClient restHighLevelClient : restHighLevelClients.values()) { - assertThat(restHighLevelClient.getLowLevelClient()).isNotSameAs(restClient); - } }); } - @Test - void configureWhenHighLevelClientIsNotAvailableShouldCreateRestClientOnly() { - this.contextRunner.withClassLoader(new FilteredClassLoader(RestHighLevelClient.class)) - .run((context) -> assertThat(context).hasSingleBean(RestClient.class) - .doesNotHaveBean(RestHighLevelClient.class)); - } - @Test void configureWhenBuilderCustomizerShouldApply() { this.contextRunner.withUserConfiguration(BuilderCustomizerConfiguration.class).run((context) -> { - 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"); + assertThat(context).hasSingleBean(RestHighLevelClient.class); + RestHighLevelClient restClient = context.getBean(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"); }); } @@ -124,17 +99,17 @@ class ElasticsearchRestClientAutoConfigurationTests { @Deprecated void configureWhenDeprecatedBuilderCustomizerShouldApply() { this.contextRunner.withUserConfiguration(DeprecatedBuilderCustomizerConfiguration.class).run((context) -> { - assertThat(context).hasSingleBean(RestClient.class); - RestClient restClient = context.getBean(RestClient.class); - assertThat(restClient).hasFieldOrPropertyWithValue("pathPrefix", "/deprecated"); + assertThat(context).hasSingleBean(RestHighLevelClient.class); + RestHighLevelClient restClient = context.getBean(RestHighLevelClient.class); + assertThat(restClient.getLowLevelClient()).hasFieldOrPropertyWithValue("pathPrefix", "/deprecated"); }); } @Test void configureWithNoTimeoutsApplyDefaults() { this.contextRunner.run((context) -> { - assertThat(context).hasSingleBean(RestClient.class); - RestClient restClient = context.getBean(RestClient.class); + assertThat(context).hasSingleBean(RestHighLevelClient.class); + RestHighLevelClient restClient = context.getBean(RestHighLevelClient.class); assertTimeouts(restClient, Duration.ofMillis(RestClientBuilder.DEFAULT_CONNECT_TIMEOUT_MILLIS), Duration.ofMillis(RestClientBuilder.DEFAULT_SOCKET_TIMEOUT_MILLIS)); }); @@ -144,16 +119,16 @@ class ElasticsearchRestClientAutoConfigurationTests { void configureWithCustomTimeouts() { this.contextRunner.withPropertyValues("spring.elasticsearch.rest.connection-timeout=15s", "spring.elasticsearch.rest.read-timeout=1m").run((context) -> { - assertThat(context).hasSingleBean(RestClient.class); - RestClient restClient = context.getBean(RestClient.class); + assertThat(context).hasSingleBean(RestHighLevelClient.class); + RestHighLevelClient restClient = context.getBean(RestHighLevelClient.class); assertTimeouts(restClient, Duration.ofSeconds(15), Duration.ofMinutes(1)); }); } - private static void assertTimeouts(RestClient restClient, Duration connectTimeout, Duration readTimeout) { - assertThat(restClient).extracting("client.defaultConfig.socketTimeout") + private static void assertTimeouts(RestHighLevelClient restClient, Duration connectTimeout, Duration readTimeout) { + assertThat(restClient.getLowLevelClient()).extracting("client.defaultConfig.socketTimeout") .isEqualTo(Math.toIntExact(readTimeout.toMillis())); - assertThat(restClient).extracting("client.defaultConfig.connectTimeout") + assertThat(restClient.getLowLevelClient()).extracting("client.defaultConfig.connectTimeout") .isEqualTo(Math.toIntExact(connectTimeout.toMillis())); } @@ -177,7 +152,7 @@ class ElasticsearchRestClientAutoConfigurationTests { void configureUriWithUsernameOnly() { this.contextRunner.withPropertyValues("spring.elasticsearch.rest.uris=http://user@localhost:9200") .run((context) -> { - RestClient client = context.getBean(RestClient.class); + RestClient client = context.getBean(RestHighLevelClient.class).getLowLevelClient(); assertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString)) .containsExactly("http://localhost:9200"); assertThat(client).extracting("client") @@ -196,7 +171,7 @@ class ElasticsearchRestClientAutoConfigurationTests { void configureUriWithUsernameAndEmptyPassword() { this.contextRunner.withPropertyValues("spring.elasticsearch.rest.uris=http://user:@localhost:9200") .run((context) -> { - RestClient client = context.getBean(RestClient.class); + RestClient client = context.getBean(RestHighLevelClient.class).getLowLevelClient(); assertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString)) .containsExactly("http://localhost:9200"); assertThat(client).extracting("client") @@ -217,7 +192,7 @@ class ElasticsearchRestClientAutoConfigurationTests { .withPropertyValues("spring.elasticsearch.rest.uris=http://user:password@localhost:9200,localhost:9201", "spring.elasticsearch.rest.username=admin", "spring.elasticsearch.rest.password=admin") .run((context) -> { - RestClient client = context.getBean(RestClient.class); + RestClient client = context.getBean(RestHighLevelClient.class).getLowLevelClient(); assertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString)) .containsExactly("http://localhost:9200", "http://localhost:9201"); assertThat(client).extracting("client") @@ -236,16 +211,6 @@ class ElasticsearchRestClientAutoConfigurationTests { }); } - @Configuration(proxyBeanMethods = false) - static class CustomRestClientConfiguration { - - @Bean - RestClient customRestClient() { - return mock(RestClient.class); - } - - } - @Configuration(proxyBeanMethods = false) static class BuilderCustomizerConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 3c0524f3e05..879754b4485 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -4691,9 +4691,10 @@ Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elastics [[boot-features-connecting-to-elasticsearch-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 and the "High Level" client. +Spring Boot provides support for the "High Level" client, which ships with `org.elasticsearch.client:elasticsearch-rest-high-level-client`. -If you have the `org.elasticsearch.client:elasticsearch-rest-client` dependency on the classpath, Spring Boot will auto-configure and register a `RestClient` bean that by default targets `http://localhost:9200`. -You can further tune how `RestClient` is configured, as shown in the following example: +If you have this dependency on the classpath, Spring Boot will auto-configure and register a `RestHighLevelClient` bean that by default targets `http://localhost:9200`. +You can further tune how `RestHighLevelClient` is configured, as shown in the following example: [source,properties,indent=0,configprops] ---- @@ -4706,8 +4707,7 @@ You can further tune how `RestClient` is configured, as shown in the following e You can also register an arbitrary number of beans that implement `RestClientBuilderCustomizer` for more advanced customizations. To take full control over the registration, define a `RestClientBuilder` bean. -If you have the `org.elasticsearch.client:elasticsearch-rest-high-level-client` dependency on the classpath, Spring Boot will auto-configure a `RestHighLevelClient`, which leverages any existing `RestClientBuilder` bean, reusing its HTTP configuration. - +TIP: If your application needs access to a "Low Level" `RestClient`, you can get it by calling `client.getLowLevelClient()` on the auto-configured `RestHighLevelClient`. [[boot-features-connecting-to-elasticsearch-reactive-rest]] ==== Connecting to Elasticsearch using Reactive REST clients