最新バージョンの Elasticsearch を統合する Spring Boot 2.1.X の問題
Spring boot 2 の新バージョンの spring-boot-starter-data-elasticsearch でサポートされている Elasticsearch のバージョンは 2.X ですが、Elasticsearch は実際にはバージョン 6.5.X まで開発されています。Elasticsearch の新機能をより良く使用するために、 spring-boot-starter-data-elasticsearch の依存関係を非推奨にし、代わりに Spring-data-elasticsearch を直接使用して新しいバージョンのサポートを有効にしました。
実際には、4.X バージョンはすでに Dev 状態にありますが、安定性を考慮して、十分であるという原則に従って、最新の 3.1.3 リリース バージョンを使用します。
まずgradleに依存関係を追加します
compile('org.springframework.data:spring-data-elasticsearch:3.1.3.RELEASE')
spring-boot-starter-data-elasticsearch の依存関係を削除する必要があることに注意してください。削除しないと、新しいバージョンが使用されません。
yml に elasticsearch 設定を追加する
elasticsearch:
cluster-name: wetodo-search
host: 127.0.0.1
port: 9300
pool: 5
構成クラスの書き込み
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());
}*/
}
今起動すると例外が報告されます。この例外には長い間悩まされていました。例外情報は次のとおりです。
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.
ソース コードを比較すると、上記の問題の根本はカスタム Config クラスに挿入された Bean メソッドであることがわかりました。
@Bean
public ElasticsearchOperations **elasticsearchTemplate**() {
Client client = client();
if (client != null) {
return new ElasticsearchTemplate(client);
} else {
//弹出自定义异常对象
throw new ApiException("初始化Elasticsearch失败!", 100011);
}
}
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);
}
}
自動設定読み込みクラスにはコンバータがあります。。。。。。OK、関数名を次のように修正しました。
@Bean
public ElasticsearchOperations elasticsearchTemplateCustom() {
Client client = client();
if (client != null) {
log.info("初始化Elasticsearch成功!");
return new ElasticsearchTemplate(client);
} else {
//弹出自定义异常对象
throw new ApiException("初始化Elasticsearch失败!", 100011);
}
}
再起動すると問題は解決しました。
application.yml に表示される Spring 独自の自動構成クラスを無効にすることもできます。
spring
autoconfigure:
#禁用Spring boot自身的自动配置类
exclude: org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration
も解決できます。