如何通過spring-boot-2.* + spring-data-elasticsearch構(gòu)建基于 HighLevelRestClient 的 ElasticsearchRestTemplate阳欲,而不是基于 Transport 的 ElasticsearchTemplate?
1. 網(wǎng)上使用spring-boot + spring-data-elasticsearch 配置的文章佩捞,實(shí)際上都不是 ElasticsearchRestTemplate权纤,而是 ElasticsearchTemplate洒嗤。
幾乎網(wǎng)上所有使用spring-boot + spring-data-elasticsearch 注解配置的文章利朵,無論標(biāo)題是否寫著使用ElasticsearchRestTemplate,配置出來的都是使用 transport 的 ElasticsearchTemplate,而不是使用 HighLevelRestClient 的 ElasticsearchRestTemplate。只有少數(shù)幾篇使用 xml 來配置的文章惧所,配置出來的是 ElasticsearchRestTemplate骤坐。
我們來看看最常見的配法,它實(shí)際上配置出來的是基于 transport 的ElasticsearchTemplate下愈。
ElasticsearchTemplate當(dāng)然可以使用了纽绍。但是,ES 官方從 v6.* 開始就deprecated了這個(gè)接口驰唬,且宣稱從 v8.* 開始顶岸,將不再支持基于 transport 的接口。所以我們暫時(shí)用用還行叫编,新項(xiàng)目還是不要再用了,改為使用基于 rest 接口的 ElasticsearchRestTemplate 比較好霹抛。
首先搓逾,在 application.properties中配置
# 這里要配置你實(shí)際的cluster名字。我用的 ES 官方docker容器杯拐,因此其名字是:
spring.data.elasticsearch.cluster-name=docker-cluster
# 這里配置 ES node 地址霞篡。
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.elasticsearch.repositories.enable=true
注意到配置的地址是
localhost:9300
,9300端口根本不是 rest 接口使用的端逼,而是 ES 內(nèi)部節(jié)點(diǎn)之間進(jìn)行管理使用的 tcp 接口朗兵。
- transport 接口就是使用 9300 端口將自己偽裝成為 cluster 的一個(gè)節(jié)點(diǎn),然后通過管理接口進(jìn)行操作的顶滩。
- rest 接口使用的是 9200 端口余掖,通過 restful 的http接口進(jìn)行訪問。
然后使用注解@EnableElasticsearchRepositories
來啟用 spring-data-elasticsearch 的自動(dòng)配置
@SpringBootApplication
@ComponentScan(basePackages= {"cn.fredworks"})
@EnableElasticsearchRepositories
public class WebApplicationQbank extends SpringBootServletInitializer {
接下來礁鲁,我們就可以使用 ElasticsearchCrudRepository 或 ElasticsearchTemplate 了盐欺。
這是使用 ElasticsearchCrudRepository 的例子:
@Repository
public interface IQuestionDao extends ElasticsearchCrudRepository<Question, String> {
}
這是使用 ElasticsearchTemplate 的例子:
@RunWith(SpringRunner.class)
@SpringBootTest(classes=WebApplicationQbank.class)
class IQuestionMaintainServiceTest {
@Resource(name = "elasticsearchTemplate")
private ElasticsearchTemplate esRestTemplate;
這個(gè)注入本身就證明了 上面的配置生成的是 ElasticsearchTemplate 而不是 ElasticsearchRestTemplate,否則這個(gè)注入會(huì)因?yàn)轭愋娃D(zhuǎn)換失敗而報(bào)錯(cuò)仅醇。
2. 一種正確的ElasticsearchRestTemplate配置
實(shí)際上冗美,spring-data的所有自動(dòng)配置,幾乎都使用了類似 @ConditionalOnMissingBean/@ConditionalOnBean 這樣的條件語句析二。spring-data-elasticsearch 自動(dòng)配置 ElasticsearchTemplate 也是這樣粉洼。因此,如果我們自己裝配一個(gè) ElasticsearchRestTemplate 實(shí)例出來叶摄,那么就可以阻止 ElasticsearchTemplate 的生成了属韧。因?yàn)闊o論是 ElasticsearchOperation 還是 ElasticsearchTemplate 還是 ElasticsearchRestTemplate,其生成的bean都叫做 "elasticsearchTemplate"准谚,只能有一個(gè)挫剑。我們可以看看 ElasticsearchDataConfiguration.RestClientConfiguration
的內(nèi)容:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestHighLevelClient.class)
static class RestClientConfiguration {
@Bean
@ConditionalOnMissingBean(value = ElasticsearchOperations.class, name = "elasticsearchTemplate")
@ConditionalOnBean(RestHighLevelClient.class)
ElasticsearchRestTemplate elasticsearchTemplate(RestHighLevelClient client, ElasticsearchConverter converter,
ResultsMapper resultsMapper) {
return new ElasticsearchRestTemplate(client, converter, resultsMapper);
}
}
當(dāng)滿足如下兩個(gè)條件時(shí),才會(huì)生成 ElasticsearchRestTemplate
- 類路徑中有 RestHighLevelClient
- 還沒有名字叫做 elasticsearchTemplate 柱衔,且類型為 ElasticsearchOperations.class 的 bean 存在樊破。實(shí)際上愉棱,ElasticsearchTemplate 和 ElasticsearchRestTemplate 都是 ElasticsearchOperation 的實(shí)現(xiàn)。
因?yàn)閟pring-data-elasticsearch 的自動(dòng)配置具有最低的優(yōu)先級(jí)哲戚,我們自己提供的@Configuration 優(yōu)先級(jí)較高奔滑,因此我們提供一個(gè)自己的 @Configuratioin 去構(gòu)建 ElasticsearchRestTemplate。它會(huì)先于spring-data-elasticsearch 自動(dòng)組裝的 ElasticsearchTemplate構(gòu)建顺少。因此朋其,我們可以按照如下步驟來配置:
首先,在 application.properties 中配置訪問端口 9200:
# 這里要配置你實(shí)際的cluster名字脆炎。我用的 ES 官方docker容器梅猿,因此其名字是:
spring.data.elasticsearch.cluster-name=docker-cluster
# 這里配置 ES node 地址,必須是 9200 端口秒裕。
spring.data.elasticsearch.cluster-nodes=localhost:9200
spring.data.elasticsearch.repositories.enable=true
然后袱蚓,實(shí)現(xiàn)配置對象:
@Configuration
public class ElasticsearchConfig {
/**
* 使用sprnig-data-elasticsearch 自動(dòng)提供的 RestHighLevelClient等構(gòu)建 ElasticsearchRestTemplate
* 2020年3月18日 下午3:05:55 xx添加此方法
* @param client
* @param converter
* @param resultsMapper
* @return
*/
@Bean
public ElasticsearchRestTemplate elasticsearchTemplate(RestHighLevelClient client, ElasticsearchConverter converter,
ResultsMapper resultsMapper) {
return new ElasticsearchRestTemplate(client, converter, resultsMapper);
}
}
接下來我們就可以直接使用了:
@RunWith(SpringRunner.class)
@SpringBootTest(classes=WebApplicationQbank.class)
class IQuestionMaintainServiceTest {
@Resource(name = QbankModuleBeanNames.QbankModuleElasticsearchTemplate)
private ElasticsearchRestTemplate esRestTemplate;
/**
* 2020年3月12日 上午9:59:44 xx添加此方法
* @throws java.lang.Exception
*/
@BeforeEach
void setUp() throws Exception {
assertNotNull(this.esRestTemplate);
assertEquals(ElasticsearchRestTemplate.class, this.esRestTemplate.getClass());
}