ElasticSearch:SpringBoot中连接单机与集群ES的通用连接配置(集群连接时使用ssl认证)

1. 背景

  1. 在做项目的过程,我们通常在本地开发时,需要连接单机的es进行测试,但是正式上线后,需要连接ES集群,并需要ssl认证,这种情况下,既要满足本地开发的需要,又要满足上线后集群的连接配置,故写下本文,用来记录
  2. 我比较希望在SpringBoot启动的时候,就建立es连接,故使用了 @PostConstruct 注解,详见下文。

2. SpringBoot连接单机或集群ES

2.1 首先定义外部文件elasticsearch.properties

我将该文件存放在src/main/resources/config/elasticsearch.properties下【该文件当然也可以写在不同环境的yml文件中】

#ES配置文件
#是否是单机
elasticsearch.isSingleton=true
#ca位置
elasticsearch.capath=src/main/resources/ca/xxxx
#这个参数暂时保留
elasticsearch.keystorepass=
#账号密码
elasticsearch.username=username
elasticsearch.password=password
# 三个es节点信息
elasticsearch.node1Ip=11.14.11.72
elasticsearch.node1Port=9200
elasticsearch.node1Scheme=http
elasticsearch.node2Ip=22.94.239.72
elasticsearch.node2Port=9200
elasticsearch.node2Scheme=http
elasticsearch.node3Ip=33.94.239.72
elasticsearch.node3Port=9200
elasticsearch.node3Scheme=http

2.2 配置一个bean读取上述配置

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;


@Data
@Component
@ConfigurationProperties(prefix = "elasticsearch")
@PropertySource(value = {"classpath:config/elasticsearch.properties"}, encoding = "utf-8")
public class ESConfig {

    private Boolean isSingleton;

    private String capath;

    private String keystorepass;

    private String username;

    private String password;

    private String node1Ip;

    private Integer node1Port;

    private String node1Scheme;

    private String node2Ip;

    private Integer node2Port;

    private String node2Scheme;

    private String node3Ip;

    private Integer node3Port;

    private String node3Scheme;

}

2.3 ES连接配置类

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;


@Slf4j
@Component
public class ESClient {

    public RestHighLevelClient restHighLevelClient;

    @Autowired
    private ESConfig esConfig;

    @PostConstruct
    private void init() {
        //初始化RestHighLevelClient
        this.initRestHighLevelClient();
    }

    private ESClient() {
    }

    private void initRestHighLevelClient() {
        try {
            if (restHighLevelClient == null) {
                if (!esConfig.getIsSingleton()) {
                    //正式环境 使用ssl认证 集群连接
                    log.info("******************ES集群连接开始****************");
                    restHighLevelClient = getClusterHighLevelClient();
                    log.info("******************ES集群连接成功****************");
                    return;
                }
                //单机连接
                log.info("******************单机ES连接开始****************");
                restHighLevelClient = getSingleHighLevelClient();
                log.info("******************单机ES连接成功****************");
            }
        } catch (Exception e) {
            log.error("es连接出现异常:{}", e.toString());
        }
    }

    /**
     * 集群连接
     *
     * @return
     * @throws Exception
     */
    private RestHighLevelClient getClusterHighLevelClient() throws Exception {
        Path trustStorePath = Paths.get(esConfig.getCapath());
        KeyStore truststore = KeyStore.getInstance("pkcs12");

        String keyStorePass = esConfig.getKeystorepass();
        InputStream is = Files.newInputStream(trustStorePath);
        truststore.load(is, keyStorePass.toCharArray());

        SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
        final SSLContext sslContext = sslBuilder.build();

        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(esConfig.getUsername(), esConfig.getPassword()));
        log.info("连接ES集群: {}:{},{}:{},{}:{}", esConfig.getNode1Ip(), esConfig.getNode1Port(), esConfig.getNode2Ip(), esConfig.getNode2Port(), esConfig.getNode3Ip(), esConfig.getNode3Port());
        RestClientBuilder rclientBuilder = RestClient.builder(
                new HttpHost(esConfig.getNode1Ip(), esConfig.getNode1Port(), esConfig.getNode1Scheme()),
                new HttpHost(esConfig.getNode2Ip(), esConfig.getNode2Port(), esConfig.getNode2Scheme()),
                new HttpHost(esConfig.getNode3Ip(), esConfig.getNode3Port(), esConfig.getNode3Scheme()))
                .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                        return httpClientBuilder.setSSLContext(sslContext)
                                .setSSLHostnameVerifier(new NoopHostnameVerifier())
                                .setDefaultCredentialsProvider(credentialsProvider);
                    }
                });
        restHighLevelClient = new RestHighLevelClient(rclientBuilder);
        return restHighLevelClient;
    }

    /**
     * 单机连接
     *
     * @return
     * @throws Exception
     */
    private RestHighLevelClient getSingleHighLevelClient() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esConfig.getUsername(), esConfig.getPassword()));
        log.info("连接单机ES: {}:{}", esConfig.getNode1Ip(), esConfig.getNode1Port());
        RestClientBuilder rclientBuilder = RestClient.builder(new HttpHost(esConfig.getNode1Ip(), esConfig.getNode1Port(), esConfig.getNode1Scheme()))
                .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                        return httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier())
                                .setDefaultCredentialsProvider(credentialsProvider);
                    }
                });
        restHighLevelClient = new RestHighLevelClient(rclientBuilder);
        return restHighLevelClient;
    }

}

3. 测试

import com.alibaba.fastjson.JSONObject;
import com.qs.myspringboottest.config.dbconnected.ESClient;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;


@RunWith(SpringRunner.class)
@SpringBootTest
public class ServiceTest1 {

    @Autowired
    private ESClient esClient;

    @Test
    public void myTest2() throws IOException {
       //获取esclient
        RestHighLevelClient restHighLevelClient = esClient.restHighLevelClient;
        SearchRequest searchRequest = new SearchRequest("indexTest");
        
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.matchAllQuery());
        
        searchRequest.source(builder);

        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSONObject.toJSONString(searchResponse));
    }
}

然后在SpringBoot启动过程中就会建立ES连接

2021-06-08 14:37:05.496  INFO 22736 --- [           main] c.q.m.config.dbconnected.ESClient        : ******************单机ES连接开始****************
2021-06-08 14:37:05.499  INFO 22736 --- [           main] c.q.m.config.dbconnected.ESClient        : 连接单机ES: 11.14.11.72:9200
2021-06-08 14:37:08.312  INFO 22736 --- [           main] c.q.m.config.dbconnected.ESClient        : ******************单机ES连接结束****************
连接开启了SSLElasticsearch集群,需要使用Java的TransportClient,并使用SSLContext来设置SSL连接。以下是一个简单的示例代码: ```java import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.transport.client.PreBuiltTransportClient; import javax.net.ssl.SSLContext; import java.net.InetAddress; import java.security.KeyStore; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class ESClient { public static void main(String[] args) throws Exception { Settings settings = Settings.builder() .put("cluster.name", "myClusterName") .put("xpack.security.user", "myUsername:myPassword") .put("xpack.security.transport.ssl.enabled", true) .put("xpack.security.transport.ssl.verification_mode", "certificate") .put("xpack.security.transport.ssl.keystore.path", "/path/to/keystore.jks") .put("xpack.security.transport.ssl.truststore.path", "/path/to/truststore.jks") .build(); SSLContext sslContext = SSLContext.getInstance("TLS"); KeyStore keyStore = KeyStore.getInstance("jks"); KeyStore trustStore = KeyStore.getInstance("jks"); keyStore.load(ESClient.class.getResourceAsStream("/path/to/keystore.jks"), "keystore_password".toCharArray()); trustStore.load(ESClient.class.getResourceAsStream("/path/to/truststore.jks"), "truststore_password".toCharArray()); TrustManager[] trustManagers = new TrustManager[] { new X509TrustManager() { public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {} public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}; sslContext.init(null, trustManagers, new SecureRandom()); TransportClient client = new PreBuiltTransportClient(settings) .addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300)) .setSSLContext(sslContext); XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject().field("name", "John").endObject(); client.prepareIndex("myindex", "mytype", "1") .setSource(builder) .get(); client.close(); } } ``` 在这个示例代码,我们首先使用Elasticsearch的TransportClient创建了一个连接,然后设置了连接ES集群所需的一些参数。其,`xpack.security.user`参数是用于认证的用户名和密码,`xpack.security.transport.ssl.enabled`参数设置为`true`表示开启SSL连接,`xpack.security.transport.ssl.verification_mode`参数设置为`certificate`表示只信任CA签署的证书。最后,我们设置了keystore和truststore的路径,并使用SSLContext将其加载。 接下来,我们使用TransportClient发送了一个简单的索引请求,将一个JSON文档插入到名为`myindex`、类型为`mytype`、ID为`1`的索引。 注意,这只是一个简单的示例,实际应用还需要根据实际情况进行配置和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值