Skip to content

Commit 16c521a

Browse files
committed
Auto-configure reactive Elasticsearch components
As of Spring Data Moore, a new reactive template and the corresponding repositories support have been added. This commit auto-configures a `ReactiveElasticsearchTemplate` with the configuration properties under the `spring.data.elasticsearch.client.reactive` namespace. To enable this feature, applications require both Spring Data Elasticsearch dependencies (typically `spring-boot-starter-data-elasticsearch`) and dependencies for a `WebClient` (often `spring-boot-starter-webflux`). The support for the reactive Elasticsearch repositories is also provided. Closes gh-16214
1 parent 05ad955 commit 16c521a

16 files changed

+711
-27
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,30 @@
2424
import org.springframework.context.annotation.Import;
2525
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
2626
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
27+
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
2728

2829
/**
2930
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch
3031
* support.
3132
* <p>
32-
* Registers an {@link ElasticsearchTemplate} if no other bean of the same type is
33-
* configured.
33+
* Registers an {@link ElasticsearchTemplate} if no other bean of the same type and the
34+
* same name {@code "elasticsearchTemplate"} is configured.
3435
*
3536
* @author Brian Clozel
3637
* @author Artur Konczak
3738
* @author Mohsin Husen
3839
* @see EnableElasticsearchRepositories
40+
* @see EnableReactiveElasticsearchRepositories
3941
* @since 1.1.0
4042
*/
4143
@Configuration(proxyBeanMethods = false)
4244
@ConditionalOnClass({ ElasticsearchTemplate.class })
4345
@AutoConfigureAfter({ ElasticsearchAutoConfiguration.class,
44-
RestClientAutoConfiguration.class })
46+
RestClientAutoConfiguration.class, ReactiveRestClientAutoConfiguration.class })
4547
@Import({ ElasticsearchDataConfiguration.BaseConfiguration.class,
4648
ElasticsearchDataConfiguration.TransportClientConfiguration.class,
47-
ElasticsearchDataConfiguration.RestHighLevelClientConfiguration.class })
49+
ElasticsearchDataConfiguration.RestClientConfiguration.class,
50+
ElasticsearchDataConfiguration.ReactiveRestClientConfiguration.class })
4851
public class ElasticsearchDataAutoConfiguration {
4952

5053
}

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

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

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

19+
import org.elasticsearch.action.support.IndicesOptions;
20+
import org.elasticsearch.action.support.WriteRequest;
1921
import org.elasticsearch.client.Client;
2022
import org.elasticsearch.client.RestHighLevelClient;
2123

@@ -24,12 +26,20 @@
2426
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2527
import org.springframework.context.annotation.Bean;
2628
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
30+
import org.springframework.data.elasticsearch.core.DefaultEntityMapper;
31+
import org.springframework.data.elasticsearch.core.DefaultResultMapper;
2732
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
2833
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
2934
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
35+
import org.springframework.data.elasticsearch.core.EntityMapper;
36+
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
37+
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate;
38+
import org.springframework.data.elasticsearch.core.ResultsMapper;
3039
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
3140
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
3241
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
42+
import org.springframework.web.reactive.function.client.WebClient;
3343

3444
/**
3545
* Configuration classes for Spring Data for Elasticsearch
@@ -57,19 +67,33 @@ public SimpleElasticsearchMappingContext mappingContext() {
5767
return new SimpleElasticsearchMappingContext();
5868
}
5969

70+
@Bean
71+
public EntityMapper entityMapper(
72+
SimpleElasticsearchMappingContext mappingContext) {
73+
return new DefaultEntityMapper(mappingContext);
74+
}
75+
76+
@Bean
77+
@ConditionalOnMissingBean
78+
public ResultsMapper resultsMapper(
79+
SimpleElasticsearchMappingContext mappingContext,
80+
EntityMapper entityMapper) {
81+
return new DefaultResultMapper(mappingContext, entityMapper);
82+
}
83+
6084
}
6185

6286
@Configuration(proxyBeanMethods = false)
6387
@ConditionalOnClass(RestHighLevelClient.class)
64-
static class RestHighLevelClientConfiguration {
88+
static class RestClientConfiguration {
6589

6690
@Bean
6791
@ConditionalOnMissingBean(value = ElasticsearchOperations.class,
6892
name = "elasticsearchTemplate")
6993
@ConditionalOnBean(RestHighLevelClient.class)
7094
public ElasticsearchRestTemplate elasticsearchTemplate(RestHighLevelClient client,
71-
ElasticsearchConverter converter) {
72-
return new ElasticsearchRestTemplate(client, converter);
95+
ElasticsearchConverter converter, ResultsMapper resultsMapper) {
96+
return new ElasticsearchRestTemplate(client, converter, resultsMapper);
7397
}
7498

7599
}
@@ -83,9 +107,9 @@ static class TransportClientConfiguration {
83107
name = "elasticsearchTemplate")
84108
@ConditionalOnBean(Client.class)
85109
public ElasticsearchTemplate elasticsearchTemplate(Client client,
86-
ElasticsearchConverter converter) {
110+
ElasticsearchConverter converter, ResultsMapper resultsMapper) {
87111
try {
88-
return new ElasticsearchTemplate(client, converter);
112+
return new ElasticsearchTemplate(client, converter, resultsMapper);
89113
}
90114
catch (Exception ex) {
91115
throw new IllegalStateException(ex);
@@ -94,4 +118,24 @@ public ElasticsearchTemplate elasticsearchTemplate(Client client,
94118

95119
}
96120

121+
@Configuration(proxyBeanMethods = false)
122+
@ConditionalOnClass({ WebClient.class, ReactiveElasticsearchOperations.class })
123+
static class ReactiveRestClientConfiguration {
124+
125+
@Bean
126+
@ConditionalOnMissingBean(value = ReactiveElasticsearchOperations.class,
127+
name = "reactiveElasticsearchTemplate")
128+
@ConditionalOnBean(ReactiveElasticsearchClient.class)
129+
public ReactiveElasticsearchTemplate reactiveElasticsearchTemplate(
130+
ReactiveElasticsearchClient client, ElasticsearchConverter converter,
131+
ResultsMapper resultsMapper) {
132+
ReactiveElasticsearchTemplate template = new ReactiveElasticsearchTemplate(
133+
client, converter, resultsMapper);
134+
template.setIndicesOptions(IndicesOptions.strictExpandOpenAndForbidClosed());
135+
template.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
136+
return template;
137+
}
138+
139+
}
140+
97141
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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.springframework.boot.autoconfigure.EnableAutoConfiguration;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.context.annotation.Import;
25+
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
26+
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
27+
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
28+
import org.springframework.data.elasticsearch.repository.support.ReactiveElasticsearchRepositoryFactoryBean;
29+
30+
/**
31+
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch
32+
* Reactive Repositories.
33+
*
34+
* @author Brian Clozel
35+
* @see EnableReactiveElasticsearchRepositories
36+
* @since 2.2.0
37+
*/
38+
@Configuration(proxyBeanMethods = false)
39+
@ConditionalOnClass({ ReactiveElasticsearchClient.class,
40+
ReactiveElasticsearchRepository.class })
41+
@ConditionalOnProperty(prefix = "spring.data.elasticsearch.repositories",
42+
name = "enabled", havingValue = "true", matchIfMissing = true)
43+
@ConditionalOnMissingBean(ReactiveElasticsearchRepositoryFactoryBean.class)
44+
@Import(ReactiveElasticsearchRepositoriesRegistrar.class)
45+
public class ReactiveElasticsearchRepositoriesAutoConfiguration {
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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 java.lang.annotation.Annotation;
20+
21+
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
22+
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
23+
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
24+
import org.springframework.data.elasticsearch.repository.config.ReactiveElasticsearchRepositoryConfigurationExtension;
25+
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
26+
27+
/**
28+
* {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Elasticsearch
29+
* Reactive Repositories.
30+
*
31+
* @author Brian Clozel
32+
* @since 2.2.0
33+
*/
34+
class ReactiveElasticsearchRepositoriesRegistrar
35+
extends AbstractRepositoryConfigurationSourceSupport {
36+
37+
@Override
38+
protected Class<? extends Annotation> getAnnotation() {
39+
return EnableReactiveElasticsearchRepositories.class;
40+
}
41+
42+
@Override
43+
protected Class<?> getConfiguration() {
44+
return EnableElasticsearchRepositoriesConfiguration.class;
45+
}
46+
47+
@Override
48+
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
49+
return new ReactiveElasticsearchRepositoryConfigurationExtension();
50+
}
51+
52+
@EnableReactiveElasticsearchRepositories
53+
private static class EnableElasticsearchRepositoriesConfiguration {
54+
55+
}
56+
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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 reactor.netty.http.client.HttpClient;
20+
21+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
25+
import org.springframework.boot.context.properties.PropertyMapper;
26+
import org.springframework.context.annotation.Bean;
27+
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.data.elasticsearch.client.ClientConfiguration;
29+
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
30+
import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients;
31+
import org.springframework.http.HttpHeaders;
32+
import org.springframework.web.reactive.function.client.WebClient;
33+
34+
/**
35+
* {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch Reactive REST
36+
* clients.
37+
*
38+
* @author Brian Clozel
39+
* @since 2.2.0
40+
*/
41+
@Configuration(proxyBeanMethods = false)
42+
@ConditionalOnClass({ ReactiveRestClients.class, WebClient.class, HttpClient.class })
43+
@EnableConfigurationProperties(ReactiveRestClientProperties.class)
44+
public class ReactiveRestClientAutoConfiguration {
45+
46+
@Bean
47+
@ConditionalOnMissingBean
48+
public ClientConfiguration clientConfiguration(
49+
ReactiveRestClientProperties properties) {
50+
ClientConfiguration.MaybeSecureClientConfigurationBuilder builder = ClientConfiguration
51+
.builder().connectedTo(properties.getEndpoints().toArray(new String[0]));
52+
if (properties.isUseSsl()) {
53+
builder.usingSsl();
54+
}
55+
configureTimeouts(builder, properties);
56+
return builder.build();
57+
}
58+
59+
private void configureTimeouts(
60+
ClientConfiguration.TerminalClientConfigurationBuilder builder,
61+
ReactiveRestClientProperties properties) {
62+
PropertyMapper map = PropertyMapper.get();
63+
map.from(properties.getConnectionTimeout()).whenNonNull()
64+
.to(builder::withConnectTimeout);
65+
map.from(properties.getSocketTimeout()).whenNonNull()
66+
.to(builder::withSocketTimeout);
67+
map.from(properties.getUsername()).whenHasText().to((username) -> {
68+
HttpHeaders headers = new HttpHeaders();
69+
headers.setBasicAuth(username, properties.getPassword());
70+
builder.withDefaultHeaders(headers);
71+
});
72+
}
73+
74+
@Bean
75+
@ConditionalOnMissingBean
76+
public ReactiveElasticsearchClient reactiveElasticsearchClient(
77+
ClientConfiguration clientConfiguration) {
78+
return ReactiveRestClients.create(clientConfiguration);
79+
}
80+
81+
}

0 commit comments

Comments
 (0)