Skip to content

Commit c74badd

Browse files
committed
Auto-configure Elasticsearch REST client in Spring Data
This commit auto-configures the Elasticsearch REST client support as a template for Spring Data Elasticsearch. As of this commit, using the transport client is still possible but developers should migrate. This commit also removes the deprecated annotation on the Elasticsearch auto-configuration for the transport client, since this deprecation notice is already present on the configuration property. Closes gh-17024 Closes gh-16542
1 parent ae5b5be commit c74badd

File tree

9 files changed

+207
-144
lines changed

9 files changed

+207
-144
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.java

-2
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,12 @@
3737
* @author Mohsin Husen
3838
* @author Andy Wilkinson
3939
* @since 1.1.0
40-
* @deprecated since 2.2.0 in favor of other auto-configured Elasticsearch clients
4140
*/
4241
@Configuration(proxyBeanMethods = false)
4342
@ConditionalOnClass({ Client.class, TransportClientFactoryBean.class })
4443
@ConditionalOnProperty(prefix = "spring.data.elasticsearch", name = "cluster-nodes",
4544
matchIfMissing = false)
4645
@EnableConfigurationProperties(ElasticsearchProperties.class)
47-
@Deprecated
4846
public class ElasticsearchAutoConfiguration {
4947

5048
private final ElasticsearchProperties properties;

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfiguration.java

+9-37
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,13 @@
1616

1717
package org.springframework.boot.autoconfigure.data.elasticsearch;
1818

19-
import org.elasticsearch.client.Client;
20-
2119
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2220
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
23-
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2421
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
26-
import org.springframework.context.annotation.Bean;
22+
import org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration;
2723
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.context.annotation.Import;
2825
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
29-
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
30-
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
31-
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
3226
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
3327

3428
/**
@@ -38,41 +32,19 @@
3832
* Registers an {@link ElasticsearchTemplate} if no other bean of the same type is
3933
* configured.
4034
*
35+
* @author Brian Clozel
4136
* @author Artur Konczak
4237
* @author Mohsin Husen
4338
* @see EnableElasticsearchRepositories
4439
* @since 1.1.0
4540
*/
4641
@Configuration(proxyBeanMethods = false)
47-
@ConditionalOnClass({ Client.class, ElasticsearchTemplate.class })
48-
@AutoConfigureAfter(ElasticsearchAutoConfiguration.class)
49-
@SuppressWarnings("deprecation")
42+
@ConditionalOnClass({ ElasticsearchTemplate.class })
43+
@AutoConfigureAfter({ ElasticsearchAutoConfiguration.class,
44+
RestClientAutoConfiguration.class })
45+
@Import({ ElasticsearchDataConfiguration.BaseConfiguration.class,
46+
ElasticsearchDataConfiguration.TransportClientConfiguration.class,
47+
ElasticsearchDataConfiguration.RestHighLevelClientConfiguration.class })
5048
public class ElasticsearchDataAutoConfiguration {
5149

52-
@Bean
53-
@ConditionalOnMissingBean
54-
@ConditionalOnBean(Client.class)
55-
public ElasticsearchTemplate elasticsearchTemplate(Client client,
56-
ElasticsearchConverter converter) {
57-
try {
58-
return new ElasticsearchTemplate(client, converter);
59-
}
60-
catch (Exception ex) {
61-
throw new IllegalStateException(ex);
62-
}
63-
}
64-
65-
@Bean
66-
@ConditionalOnMissingBean
67-
public ElasticsearchConverter elasticsearchConverter(
68-
SimpleElasticsearchMappingContext mappingContext) {
69-
return new MappingElasticsearchConverter(mappingContext);
70-
}
71-
72-
@Bean
73-
@ConditionalOnMissingBean
74-
public SimpleElasticsearchMappingContext mappingContext() {
75-
return new SimpleElasticsearchMappingContext();
76-
}
77-
7850
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.data.elasticsearch;
18+
19+
import org.elasticsearch.client.Client;
20+
import org.elasticsearch.client.RestHighLevelClient;
21+
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
28+
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
29+
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
30+
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
31+
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
32+
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
33+
34+
/**
35+
* Configuration classes for Spring Data for Elasticsearch
36+
* <p>
37+
* Those should be {@code @Import} in a regular auto-configuration class to guarantee
38+
* their order of execution.
39+
*
40+
* @author Brian Clozel
41+
*/
42+
abstract class ElasticsearchDataConfiguration {
43+
44+
@Configuration(proxyBeanMethods = false)
45+
static class BaseConfiguration {
46+
47+
@Bean
48+
@ConditionalOnMissingBean
49+
public ElasticsearchConverter elasticsearchConverter(
50+
SimpleElasticsearchMappingContext mappingContext) {
51+
return new MappingElasticsearchConverter(mappingContext);
52+
}
53+
54+
@Bean
55+
@ConditionalOnMissingBean
56+
public SimpleElasticsearchMappingContext mappingContext() {
57+
return new SimpleElasticsearchMappingContext();
58+
}
59+
60+
}
61+
62+
@Configuration(proxyBeanMethods = false)
63+
@ConditionalOnClass(RestHighLevelClient.class)
64+
static class RestHighLevelClientConfiguration {
65+
66+
@Bean
67+
@ConditionalOnMissingBean(value = ElasticsearchOperations.class,
68+
name = "elasticsearchTemplate")
69+
@ConditionalOnBean(RestHighLevelClient.class)
70+
public ElasticsearchRestTemplate elasticsearchTemplate(RestHighLevelClient client,
71+
ElasticsearchConverter converter) {
72+
return new ElasticsearchRestTemplate(client, converter);
73+
}
74+
75+
}
76+
77+
@Configuration(proxyBeanMethods = false)
78+
@ConditionalOnClass(Client.class)
79+
static class TransportClientConfiguration {
80+
81+
@Bean
82+
@ConditionalOnMissingBean(value = ElasticsearchOperations.class,
83+
name = "elasticsearchTemplate")
84+
@ConditionalOnBean(Client.class)
85+
public ElasticsearchTemplate elasticsearchTemplate(Client client,
86+
ElasticsearchConverter converter) {
87+
try {
88+
return new ElasticsearchTemplate(client, converter);
89+
}
90+
catch (Exception ex) {
91+
throw new IllegalStateException(ex);
92+
}
93+
}
94+
95+
}
96+
97+
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfigurationTests.java

+58-53
Original file line numberDiff line numberDiff line change
@@ -16,97 +16,102 @@
1616

1717
package org.springframework.boot.autoconfigure.data.elasticsearch;
1818

19-
import org.junit.jupiter.api.AfterEach;
2019
import org.junit.jupiter.api.Test;
2120
import org.testcontainers.junit.jupiter.Container;
2221
import org.testcontainers.junit.jupiter.Testcontainers;
2322

24-
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
25-
import org.springframework.boot.test.util.TestPropertyValues;
23+
import org.springframework.boot.autoconfigure.AutoConfigurations;
24+
import org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration;
25+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2626
import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
27-
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
2830
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
2931
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
3032
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
3133

3234
import static org.assertj.core.api.Assertions.assertThat;
35+
import static org.mockito.Mockito.mock;
3336

3437
/**
3538
* Tests for {@link ElasticsearchDataAutoConfiguration}.
3639
*
3740
* @author Phillip Webb
3841
* @author Artur Konczak
42+
* @author Brian Clozel
3943
*/
40-
@SuppressWarnings("deprecation")
4144
@Testcontainers
4245
public class ElasticsearchDataAutoConfigurationTests {
4346

4447
@Container
4548
public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
4649

47-
private AnnotationConfigApplicationContext context;
50+
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
51+
.withConfiguration(AutoConfigurations.of(ElasticsearchAutoConfiguration.class,
52+
RestClientAutoConfiguration.class,
53+
ElasticsearchDataAutoConfiguration.class));
4854

49-
@AfterEach
50-
public void close() {
51-
if (this.context != null) {
52-
this.context.close();
53-
}
55+
@Test
56+
public void defaultTransportBeansAreRegistered() {
57+
this.contextRunner
58+
.withPropertyValues(
59+
"spring.data.elasticsearch.cluster-nodes:localhost:"
60+
+ elasticsearch.getMappedTransportPort(),
61+
"spring.data.elasticsearch.cluster-name:docker-cluster")
62+
.run((context) -> assertThat(context)
63+
.hasSingleBean(ElasticsearchTemplate.class)
64+
.hasSingleBean(SimpleElasticsearchMappingContext.class)
65+
.hasSingleBean(ElasticsearchConverter.class));
5466
}
5567

5668
@Test
57-
public void templateBackOffWithNoClient() {
58-
this.context = new AnnotationConfigApplicationContext(
59-
ElasticsearchDataAutoConfiguration.class);
60-
assertThat(this.context.getBeansOfType(ElasticsearchTemplate.class)).isEmpty();
69+
public void defaultTransportBeansNotRegisteredIfNoTransportClient() {
70+
this.contextRunner.run((context) -> assertThat(context)
71+
.doesNotHaveBean(ElasticsearchTemplate.class));
6172
}
6273

6374
@Test
64-
public void templateExists() {
65-
this.context = new AnnotationConfigApplicationContext();
66-
TestPropertyValues
67-
.of("spring.data.elasticsearch.cluster-nodes:localhost:"
68-
+ elasticsearch.getMappedTransportPort(),
69-
"spring.data.elasticsearch.cluster-name:docker-cluster")
70-
.applyTo(this.context);
71-
this.context.register(PropertyPlaceholderAutoConfiguration.class,
72-
ElasticsearchAutoConfiguration.class,
73-
ElasticsearchDataAutoConfiguration.class);
74-
this.context.refresh();
75-
assertHasSingleBean(ElasticsearchTemplate.class);
75+
public void defaultRestBeansRegistered() {
76+
this.contextRunner.run((context) -> assertThat(context)
77+
.hasSingleBean(ElasticsearchRestTemplate.class)
78+
.hasSingleBean(ElasticsearchConverter.class));
7679
}
7780

7881
@Test
79-
public void mappingContextExists() {
80-
this.context = new AnnotationConfigApplicationContext();
81-
TestPropertyValues
82-
.of("spring.data.elasticsearch.cluster-nodes:localhost:"
83-
+ elasticsearch.getMappedTransportPort(),
84-
"spring.data.elasticsearch.cluster-name:docker-cluster")
85-
.applyTo(this.context);
86-
this.context.register(PropertyPlaceholderAutoConfiguration.class,
87-
ElasticsearchAutoConfiguration.class,
88-
ElasticsearchDataAutoConfiguration.class);
89-
this.context.refresh();
90-
assertHasSingleBean(SimpleElasticsearchMappingContext.class);
82+
public void customTransportTemplateShouldBeUsed() {
83+
this.contextRunner.withUserConfiguration(CustomTransportTemplate.class)
84+
.run((context) -> assertThat(context)
85+
.getBeanNames(ElasticsearchTemplate.class).hasSize(1)
86+
.contains("elasticsearchTemplate"));
9187
}
9288

9389
@Test
94-
public void converterExists() {
95-
this.context = new AnnotationConfigApplicationContext();
96-
TestPropertyValues
97-
.of("spring.data.elasticsearch.cluster-nodes:localhost:"
98-
+ elasticsearch.getMappedTransportPort(),
99-
"spring.data.elasticsearch.cluster-name:docker-cluster")
100-
.applyTo(this.context);
101-
this.context.register(PropertyPlaceholderAutoConfiguration.class,
102-
ElasticsearchAutoConfiguration.class,
103-
ElasticsearchDataAutoConfiguration.class);
104-
this.context.refresh();
105-
assertHasSingleBean(ElasticsearchConverter.class);
90+
public void customRestTemplateShouldBeUsed() {
91+
this.contextRunner.withUserConfiguration(CustomRestTemplate.class)
92+
.run((context) -> assertThat(context)
93+
.getBeanNames(ElasticsearchRestTemplate.class).hasSize(1)
94+
.contains("elasticsearchTemplate"));
95+
}
96+
97+
@Configuration
98+
static class CustomTransportTemplate {
99+
100+
@Bean
101+
ElasticsearchTemplate elasticsearchTemplate() {
102+
return mock(ElasticsearchTemplate.class);
103+
}
104+
106105
}
107106

108-
private void assertHasSingleBean(Class<?> type) {
109-
assertThat(this.context.getBeanNamesForType(type)).hasSize(1);
107+
@Configuration
108+
static class CustomRestTemplate {
109+
110+
@Bean
111+
ElasticsearchRestTemplate elasticsearchTemplate() {
112+
return mock(ElasticsearchRestTemplate.class);
113+
}
114+
110115
}
111116

112117
}

0 commit comments

Comments
 (0)