新版本的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);
}
}
自动配置加载类里,多了个converter。。。。。。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
也可以解决。