Un problème avec Spring boot 2.1.X intégrant la dernière version d'Elasticsearch
La version d'Elasticsearch prise en charge dans spring-boot-starter-data-elasticsearch de la nouvelle version de Spring boot 2 est 2.X, mais Elasticsearch a en fait évolué vers la version 6.5.X. Afin de mieux utiliser les nouvelles fonctionnalités d'Elasticsearch, donc Dépréciation de la dépendance spring-boot-starter-data-elasticsearch et utilisation directe à la place de Spring-data-elasticsearch pour activer la prise en charge de la nouvelle version. La correspondance de version actuelle est la suivante
En fait, la version 4.X est déjà dans l'état Dev, mais compte tenu de la stabilité, conformément au principe que trop c'est trop, utilisez la dernière version 3.1.3
Ajoutez d'abord les dépendances dans gradle
compile('org.springframework.data:spring-data-elasticsearch:3.1.3.RELEASE')
Notez que la dépendance de spring-boot-starter-data-elasticsearch doit être supprimée, sinon la nouvelle version ne sera pas utilisée
Ajouter la configuration elasticsearch dans yml
elasticsearch:
cluster-name: wetodo-search
host: 127.0.0.1
port: 9300
pool: 5
Écrire la classe de configuration
package com.wetodo.api.config;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import java.net.InetAddress;
/**
* @ClassName ElasticConfig
* @Description ElasticSearch搜索引擎配置
* @Author wangd
* @Create 2018-12-02 23:22
*/
@Configuration
@EnableElasticsearchRepositories(basePackages = "com.wetodo.api.dao")
@Slf4j
public class ElasticConfig {
/**
* 主机
*/
@Value("${elasticsearch.host}")
private String esHost;
/**
* 传输层端口,注意和ES的Restful API默认9200端口有区分
*/
@Value("${elasticsearch.port}")
private int esPort;
/**
* 集群名称
*/
@Value("${elasticsearch.clustername}")
private String esClusterName;
/**
* 连接池
*/
@Value("${elasticsearch.pool}")
private String poolSize;
@Bean
public Client client() {
log.info("开始初始化Elasticsearch");
try {
Settings esSettings = Settings.builder()
.put("cluster.name", esClusterName)
.put("client.transport.sniff", true)//增加嗅探机制,找到ES集群
.put("thread_pool.search.size", Integer.parseInt(poolSize))//增加线程池个数,暂时设为5
.build();
//https://www.elastic.co/guide/en/elasticsearch/guide/current/_transport_client_versus_node_client.html
return new PreBuiltTransportClient(esSettings)
.addTransportAddress(new TransportAddress(InetAddress.getByName(esHost), esPort));
} catch (Exception e) {
log.error("初始化Elasticsearch失败!", e);
return null;
}
}
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
Client client = client();
if (client != null) {
return new ElasticsearchTemplate(client);
} else {
//弹出自定义异常对象
throw new ApiException("初始化Elasticsearch失败!", 100011);
}
}
//Embedded Elasticsearch Server
/*@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
}*/
}
S'il est lancé maintenant, une exception sera signalée. Cette exception me préoccupe depuis longtemps. Les informations sur l'exception sont les suivantes :
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'elasticsearchTemplate' defined in class path resource [org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfiguration.class]:
Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false;
factoryBeanName=org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration; factoryMethodName=elasticsearchTemplate; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfiguration.class]] for bean 'elasticsearchTemplate': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=elasticConfig;
factoryMethodName=elasticsearchTemplate; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/wetodo/api/config/ElasticConfig.class]] bound.
En comparant le code source, j'ai trouvé que la racine du problème ci-dessus est la méthode bean injectée dans ma classe Config personnalisée
@Bean
public ElasticsearchOperations **elasticsearchTemplate**() {
Client client = client();
if (client != null) {
return new ElasticsearchTemplate(client);
} else {
//弹出自定义异常对象
throw new ApiException("初始化Elasticsearch失败!", 100011);
}
}
Le conflit de surcharge de fonction causé par le même nom et des paramètres différents que la fonction dans org.springframework.boot.autoconfigure.ElasticsearchDataAutoConfiguration
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(Client.class)
public ElasticsearchTemplate elasticsearchTemplate(Client client,
ElasticsearchConverter converter) {
try {
return new ElasticsearchTemplate(client, converter);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
Dans la classe de chargement automatique de la configuration, il y a un convertisseur. . . . . . OK, j'ai fixé le nom de ma fonction à :
@Bean
public ElasticsearchOperations elasticsearchTemplateCustom() {
Client client = client();
if (client != null) {
log.info("初始化Elasticsearch成功!");
return new ElasticsearchTemplate(client);
} else {
//弹出自定义异常对象
throw new ApiException("初始化Elasticsearch失败!", 100011);
}
}
Redémarrez, problème résolu.
Vous pouvez également désactiver la propre classe de configuration automatique de Spring affichée dans application.yml :
spring
autoconfigure:
#禁用Spring boot自身的自动配置类
exclude: org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration
peut également être résolu.