0
点赞
收藏
分享

微信扫一扫

Maven 项目集成 Elasticsearch 和 Redis

木匠0819 2022-05-04 阅读 75

文章目录


这是一个普通 Maven 项目,不是 Spring 或 SpringBoot 项目。

下面都用到了这个工具类:

package com.gtcom.search.util;

import com.gtcom.search.exception.ExceptionEnum;
import com.gtcom.search.exception.SearchException;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Properties;

/**
 * 配置文件加载工具类
 *
 * @author wangbo
 * @date 2022/2/28
 */
@Slf4j
public class LoadUtils {

    private LoadUtils() {
        throw new IllegalStateException("Utility class");
    }

    private static final String APPLICATION_PREFIX = "application-";

    /**
     * 获取运行时配置
     */
    public static Properties getProperties() {
        //只能读取到命令行的启动参数:-Dspring.profiles.active=xxx
        //读取不到配置文件中的配置项:spring.profiles.active=xxx
        String active = System.getProperty("spring.profiles.active");
        if (Objects.isNull(active)) {
            active = "dev";
        }
        log.info("current runtime environment active = [{}]", active);
        Properties props = new Properties();
        try {
        	//尝试加载properties文件
            InputStream resourceAsStream = LoadUtils.class.getClassLoader().getResourceAsStream(File.separator + APPLICATION_PREFIX + active + ".properties");
            if (Objects.nonNull(resourceAsStream)) {
                props.load(resourceAsStream);
                return props;
            }
            //尝试加载yml文件
            resourceAsStream = LoadUtils.class.getClassLoader().getResourceAsStream(File.separator + APPLICATION_PREFIX + active + ".yml");
            if (Objects.nonNull(resourceAsStream)) {
                props.load(new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8));
                return props;
            }
        } catch (IOException e) {
            log.error("load application config file exception", e);
            throw new SearchException(ExceptionEnum.CONFIG_LOAD_EXCEPTION);
        }
        log.error("not loaded into the application config file");
        throw new SearchException(ExceptionEnum.CONFIG_LOAD_EXCEPTION);
    }
}

这个工具类能读取 properties 和 yml 格式的配置文件,环境指定必须使用命令行参数的形式,否则加载不到。

1. 集成 Elasticsearch

1.1. 依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

1.2. 配置

1.2.1. 配置文件

properties

#ES新闻集群
elasticsearch.news.hosts=10.1.2.11:9200,10.1.2.12:9200,10.1.2.13:9200
elasticsearch.news.username=admin
elasticsearch.news.password=test
#ES社交集群
elasticsearch.social.hosts=10.1.2.14:9200,10.1.2.15:9200,10.1.2.16:9200
elasticsearch.social.username=admin
elasticsearch.social.password=test

yml:

#ES新闻集群
elasticsearch.news.hosts: 10.1.2.11:9200,10.1.2.12:9200,10.1.2.13:9200
elasticsearch.news.username: admin
elasticsearch.news.password: test
#ES社交集群
elasticsearch.social.hosts: 10.1.2.14:9200,10.1.2.15:9200,10.1.2.16:9200
elasticsearch.social.username: admin
elasticsearch.social.password: test

1.2.2. 配置类

package com.gtcom.search.config;

import com.gtcom.search.constant.Separators;
import com.gtcom.search.util.LoadUtils;
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.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;

import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * Elastic配置
 *
 * @author wangbo
 * @date 2021/12/7
 */
@Slf4j
public class ElasticConfig {

    private ElasticConfig() {
        throw new IllegalStateException("Utility class");
    }

    private static final RestHighLevelClient ES_NEWS_CLIENT;

    private static final RestHighLevelClient ES_SOCIAL_CLIENT;

    static {
        Properties properties = LoadUtils.getProperties();
        //初始化客户端
        String newsHosts = properties.getProperty("elasticsearch.news.hosts");
        String newsUserName = properties.getProperty("elasticsearch.news.username");
        String newsPassword = properties.getProperty("elasticsearch.news.password");
        ES_NEWS_CLIENT = init(newsHosts, newsUserName, newsPassword);

        String socialHosts = properties.getProperty("elasticsearch.social.hosts");
        String socialUserName = properties.getProperty("elasticsearch.social.username");
        String socialPassword = properties.getProperty("elasticsearch.social.password");
        ES_SOCIAL_CLIENT = init(socialHosts, socialUserName, socialPassword);
    }

    /**
     * 初始化ES集群客户端
     *
     * @param hosts    服务地址
     * @param username 用户名称
     * @param password 用户密码
     * @return ES集群客户端
     */
    private static RestHighLevelClient init(String hosts, String username, String password) {
        String[] hostArray = hosts.split(Separators.COMMA);
        HttpHost[] httpHosts = new HttpHost[hostArray.length];
        for (int i = 0; i < hostArray.length; i++) {
            httpHosts[i] = HttpHost.create(hostArray[i]);
        }
        RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);
        //设置超时时间
        restClientBuilder.setRequestConfigCallback(
                builder -> builder.setConnectTimeout(5000).setSocketTimeout(60000)
        );
        //配置身份验证和KeepAlive
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        restClientBuilder.setHttpClientConfigCallback(
                httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                        .setKeepAliveStrategy((response, context) -> TimeUnit.MINUTES.toMillis(3))
        );
        return new RestHighLevelClient(restClientBuilder);
    }

    /**
     * 获取ES新闻客户端
     */
    public static RestHighLevelClient getEsNewsClient() {
        return ES_NEWS_CLIENT;
    }

    /**
     * 获取ES社交客户端
     */
    public static RestHighLevelClient getEsSocialClient() {
        return ES_SOCIAL_CLIENT;
    }
}

1.3. 使用

下面用新闻客户端示例,社交客户端使用一样:

//查询条数
CountResponse countResponse;
try {
    countResponse = ElasticConfig.getEsNewsClient().count(countRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
    log.error("查询【新闻条数】发生异常", e);
    throw new SearchException(ExceptionEnum.ELASTIC_SEARCH_EXCEPTION);
}
//查询数据
SearchResponse searchResponse;
try {
    searchResponse = ElasticConfig.getEsNewsClient().search(searchRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
    log.error("查询【新闻数据】发生异常", e);
    throw new SearchException(ExceptionEnum.ELASTIC_SEARCH_EXCEPTION);
}

2. 集成 Redis

2.1. 依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2.2. 配置

2.2.1. 配置文件

这里支持两种配置方式:单机和哨兵。

2.2.1.1. 单机配置

单机版 properties:

#Redis配置:单机stand-alone/哨兵sentinel
redis.config.mode=stand-alone
redis.stand-alone.hosts=192.168.10.11
redis.stand-alone.port=6379

单机版 yml:

#Redis配置:单机stand-alone/哨兵sentinel
redis.config.mode: stand-alone
redis.stand-alone.hosts: 192.168.10.11
redis.stand-alone.port: 6379
2.2.1.2. 哨兵配置

哨兵版 properties:

#Redis配置:单机stand-alone/哨兵sentinel
redis.config.mode=sentinel
redis.sentinel.password=12345
redis.sentinel.master=mymaster
redis.sentinel.nodes=10.6.22.14:26380,10.6.22.14:26381,10.6.22.14:26382

哨兵版 yml:

#Redis配置:单机stand-alone/哨兵sentinel
redis.config.mode: sentinel
redis.sentinel.password: 12345
redis.sentinel.master: mymaster
redis.sentinel.nodes: 10.6.10.11:26380,10.6.10.11:26381,10.6.10.11:26382

2.2.2. 配置类

package com.gtcom.search.config;

import com.gtcom.search.exception.ExceptionEnum;
import com.gtcom.search.exception.SearchException;
import com.gtcom.search.util.LoadUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;

/**
 * Redis配置
 *
 * @author wangbo
 * @date 2022/1/24
 */
@Slf4j
public class RedisConfig {

    private RedisConfig() {
        throw new IllegalStateException("Utility class");
    }

    private static final JedisPool JEDIS_POOL;

    private static final JedisSentinelPool JEDIS_SENTINEL_POOL;

    private static final String redisConfigMode;

    static {
        //临时变量
        JedisPool jedisPool = null;
        JedisSentinelPool jedisSentinelPool = null;

        Properties properties = LoadUtils.getProperties();
        //Redis配置模式:单机stand-alone/哨兵sentinel
        redisConfigMode = properties.getProperty("redis.config.mode");
        if ("stand-alone".equals(redisConfigMode)) {
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            jedisPoolConfig.setTestOnBorrow(true);
            String hosts = properties.getProperty("redis.stand-alone.hosts");
            int port = Integer.parseInt(properties.getProperty("redis.stand-alone.port"));
            //有密码和没密码不同
            String password = properties.getProperty("redis.stand-alone.password");
            if (StringUtils.isBlank(password)) {
                jedisPool = new JedisPool(jedisPoolConfig, hosts, port);
            } else {
                jedisPool = new JedisPool(jedisPoolConfig, hosts, port, 5000, password);
            }
        } else if ("sentinel".equals(redisConfigMode)) {
            String masterName = properties.getProperty("redis.sentinel.master");
            String nodes = properties.getProperty("redis.sentinel.nodes");
            String[] split = nodes.split(",");
            HashSet<String> sentinels = new HashSet<>(Arrays.asList(split));
            String password = properties.getProperty("redis.sentinel.password");
            jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, password);
        } else {
            log.error("redis config mode error, mode = {}", redisConfigMode);
            throw new SearchException(ExceptionEnum.CONFIG_LOAD_EXCEPTION);
        }

        JEDIS_POOL = jedisPool;
        JEDIS_SENTINEL_POOL = jedisSentinelPool;
    }

    /**
     * 获取Jedis连接池
     */
    public static Jedis getJedis() {
        if ("stand-alone".equals(redisConfigMode)) {
            return JEDIS_POOL.getResource();
        } else if ("sentinel".equals(redisConfigMode)) {
            return JEDIS_SENTINEL_POOL.getResource();
        }
        return null;
    }
}

2.3. 使用

就是 Jedis 的使用方法,下面简单示例:

/**
 * 从Redis获取索引列表
 *
 * @param redisKey redis key
 * @return 索引列表
 */
public static List<String> getIndexListFromRedis(String redisKey) {
    try (Jedis jedis = RedisConfig.getJedis()) {
        assert jedis != null;
        String indexListStr = jedis.get(redisKey);
        if (StringUtils.isBlank(indexListStr)) {
            log.warn("从Redis查询索引列表为空,redisKey = {}", redisKey);
            return Collections.emptyList();
        }
        return JSON.parseArray(indexListStr).toJavaList(String.class);
    } catch (Exception e) {
        log.error("从Redis查询索引列表异常,redisKey = {}", redisKey, e);
        return Collections.emptyList();
    }
}
举报

相关推荐

0 条评论