I'm following this post which explains how to use Java High Level REST Client (JHLRC) to connect with ElasticSearch.
The important parts for this questions are in ElasticsearchConfig.java:
@Configuration
public class ElasticsearchConfig {
...
@Bean(destroyMethod = "close")
public RestHighLevelClient restClient() {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(userName, password));
RestClientBuilder builder = RestClient.builder(new HttpHost(host, port))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
RestHighLevelClient client = new RestHighLevelClient(builder);
return client;
}
}
and ProfileService.java:
@Service
public class ProfileService {
private RestHighLevelClient client;
private ObjectMapper objectMapper;
@Autowired
public ProfileService(RestHighLevelClient client, ObjectMapper objectMapper) {
this.client = client;
this.objectMapper = objectMapper;
}
...
We are autowiring RestHighLevelClient
and ObjectMapper
, so how does Spring knows that the RestHighLevelClient
instance we need comes from ElasticsearchConfig.restClient()
?
Spring does an initial scan of the classes to identify what beans it is going to make. It will then start the 'initialisation' phase.
@Bean
annotated methods in @Configuration
annotated classes will be invoked, and the result loaded into the ApplicationContext
. So the RestHighLevelClient
is created (by the method you have) and loaded.
It then tries to create the ProfileService
instance. It sees that a RestHighLevelClient
instance is required (by constructor parameter). It looks in the ApplicationContext
as well as the beans planned for creation in the scanning phase. Since there's only one RestHighLevelClient
instance there's no conflict, and so that instance is used.
From other comments:
If there are multiple RestHighLevelClient
instances either pending creation or already in the ApplicationContext
then you will get a BeanCreationException
detailing that 'too many candidates, expected 1 but found n'.
These can be worked in several ways.
You can annotate one of the RestHighLevelClient
beans as @Primary
which indicates 'use this if multiple are available, but only one required'.
You can annotate the constructor parameter with an @Qualifier
detailing which of the multiple instances to autowire.
You can change the constructor parameter to a Collection<RestHighLevelClient>
which will autowire all such instances, and then make the selection yourself in the constructor.