com.github.javaclub.toolbox.cache.RedisStoreBuilder Maven / Gradle / Ivy
/*
* @(#)RedisStoreBuilder.java 2022-12-8
*
* Copyright (c) 2022. All Rights Reserved.
*
*/
package com.github.javaclub.toolbox.cache;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.github.javaclub.AppBootConstants;
import com.github.javaclub.Constants.Environments;
import com.github.javaclub.Constants.RedisStoreConfig;
import com.github.javaclub.Constants.SpringRedisConfig;
import com.github.javaclub.toolbox.ToolBox.Maps;
import com.github.javaclub.toolbox.ToolBox.Objects;
import com.github.javaclub.toolbox.ToolBox.Reflections;
import com.github.javaclub.toolbox.ToolBox.Strings;
import com.github.javaclub.toolbox.cache.redis.RedisStore;
import com.github.javaclub.toolbox.conf.CompositeAppConfigProperties;
import com.github.javaclub.toolbox.thread.ExecutorServiceInstance;
import redis.clients.jedis.JedisPoolConfig;
/**
* RedisStoreBuilder
*
* @author Gerald Chen
* @version $Id: RedisStoreBuilder.java 2022-12-8 11:22:11 Exp $
*/
public class RedisStoreBuilder {
static final Logger log = LoggerFactory.getLogger(RedisStoreBuilder.class);
static volatile int warnTimes = 0;
static {
ExecutorServiceInstance.get().scheduleAtFixedRate(RedisStoreBuilder::doMonitor, 3L, 30L, TimeUnit.SECONDS);
}
public static RedisStore autoBuild(boolean configBuild) {
if (Thread.currentThread().isInterrupted()) {
log.warn("The currentThread is interrupted");
return null;
}
if (!configBuild) {
RedisStore store = RedisStore.defaultPublic();
if (null != store && store.isReady()) {
return store;
}
}
String host = CompositeAppConfigProperties.getInstance().getValue(RedisStoreConfig.HOST);
String password = Strings.EMPTY;
int port = -1, db = -1;
String[] configKeys = null;
if (Strings.isNotBlank(host)) { // 使用redis.xxx下的配置项
port = CompositeAppConfigProperties.getInstance().intValue(RedisStoreConfig.PORT, -1);
password = CompositeAppConfigProperties.getInstance().getValue(RedisStoreConfig.PASSWORD);
db = CompositeAppConfigProperties.getInstance().intValue(RedisStoreConfig.DB);
configKeys = RedisStoreConfig.REDIS_STORE_CONFIG;
} else if (Strings.isNotBlank(CompositeAppConfigProperties.getInstance().getValue(RedisStoreConfig.SPRING_CONFIG[0]))) {
host = CompositeAppConfigProperties.getInstance().getValue(SpringRedisConfig.HOST);
port = CompositeAppConfigProperties.getInstance().intValue(SpringRedisConfig.PORT, -1);
password = CompositeAppConfigProperties.getInstance().getValue(SpringRedisConfig.PASSWORD);
db = CompositeAppConfigProperties.getInstance().intValue(SpringRedisConfig.DATABASE);
configKeys = RedisStoreConfig.SPRING_CONFIG;
} else { // spring配置作为兜底
host = CompositeAppConfigProperties.getInstance().getValue(SpringRedisConfig.HOST);
port = CompositeAppConfigProperties.getInstance().intValue(SpringRedisConfig.PORT, -1);
password = CompositeAppConfigProperties.getInstance().getValue(SpringRedisConfig.PASSWORD);
db = CompositeAppConfigProperties.getInstance().intValue(SpringRedisConfig.DATABASE);
configKeys = RedisStoreConfig.SPRING_CONFIG;
}
port = (port == -1 ? 6379 : port); // spring redis 未配置端口,会使用默认端口6379
Object[] params = new Object[] { RedisStoreConfig.STORE_KEY_COMMON, host, port, db };
if (Strings.isAnyBlank(host, password) || port == -1 || db == -1) {
warnLog(params);
return null;
}
if (!RedisStore.test(host, port, password, db)) {
warnLog(params);
return null;
}
return RedisStore.createRedisStore(RedisStoreConfig.STORE_KEY_COMMON, configKeys);
}
public static void destroyAll() {
Map stores = RedisStore.presentAll();
RedisStore commonStore = stores.get(RedisStoreConfig.STORE_KEY_COMMON);
for (Map.Entry element : stores.entrySet()) {
if (!Strings.equals(RedisStoreConfig.STORE_KEY_COMMON, element.getKey())) {
element.getValue().destroy();
}
}
if (null != commonStore) {
commonStore.destroy();
}
}
public static JedisPoolConfig newCustomJedisPoolConfig() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 连接池最大连接数(使用负值表示没有限制)
poolConfig.setMaxTotal(CompositeAppConfigProperties.getInstance().intValue(new String[] {
"redis.pool.maxTotal", "redis.pool.max-total",
"spring.redis.jedis.pool.maxActive", "spring.redis.jedis.pool.max-active",
"spring.redis.lettuce.pool.maxActive", "spring.redis.lettuce.pool.max-active"
}, 15));
// 连接池中的最大空闲连接数
poolConfig.setMaxIdle(CompositeAppConfigProperties.getInstance().intValue(new String[] {
"redis.pool.maxIdle", "redis.pool.max-idle",
"spring.redis.jedis.pool.maxIdle", "spring.redis.jedis.pool.max-idle",
"spring.redis.lettuce.pool.maxIdle", "spring.redis.lettuce.pool.maxIdle",
}, 15));
// 连接池中的最小空闲连接
poolConfig.setMinIdle(CompositeAppConfigProperties.getInstance().intValue(new String[] {
"redis.pool.minIdle", "redis.pool.min-idle",
"spring.redis.jedis.pool.minIdle", "spring.redis.jedis.pool.min-idle",
"spring.redis.lettuce.pool.minIdle", "spring.redis.lettuce.pool.min-idle"
}, 1));
// 设置获取连接时的最大等待毫秒数(阻塞等待时间,blockWhenExhausted设置为true时才生效)
poolConfig.setMaxWaitMillis(CompositeAppConfigProperties.getInstance().longValue(new String[] {
"redis.pool.maxWaitMillis", "redis.pool.maxWait", "redis.pool.max-wait",
"spring.redis.jedis.pool.maxWait", "spring.redis.jedis.pool.max-wait",
"spring.redis.lettuce.pool.maxWait", "spring.redis.lettuce.pool.max-wait"
}, 3000L));
// 空闲资源的检测周期(毫秒)
poolConfig.setTimeBetweenEvictionRunsMillis(CompositeAppConfigProperties.getInstance().longValue(new String[] {
"redis.pool.timeBetweenEvictionRunsMillis", "redis.pool.timeBetweenEvictionRuns", "redis.pool.time-between-eviction-runs",
"spring.redis.jedis.pool.timeBetweenEvictionRuns", "spring.redis.jedis.pool.time-between-eviction-runs",
"spring.redis.lettuce.pool.timeBetweenEvictionRuns", "spring.redis.lettuce.pool.time-between-eviction-runs"
}, 10*1000L));
// 逐出连接的最小空闲时间毫秒数(15分钟)
poolConfig.setMinEvictableIdleTimeMillis(CompositeAppConfigProperties.getInstance().longValue("redis.pool.minEvictableIdleTimeMillis", 15*60*1000L)); // 连接最小空闲时间
// 每次逐出检查时逐出的最大数目,默认3
poolConfig.setNumTestsPerEvictionRun(CompositeAppConfigProperties.getInstance().intValue("redis.pool.numTestsPerEvictionRun", 3));
// 对拿到的connection进行validateObject校验
poolConfig.setTestOnBorrow(CompositeAppConfigProperties.getInstance().boolValue("redis.pool.testOnBorrow", true));
// 在进行returnObject对返回的connection进行validateObject校验
poolConfig.setTestOnReturn(CompositeAppConfigProperties.getInstance().boolValue("redis.pool.testOnReturn", false));
// 定时对线程池中空闲的链接进行校验
poolConfig.setTestWhileIdle(CompositeAppConfigProperties.getInstance().boolValue("redis.pool.testWhileIdle", true));
// 当资源池用尽后,调用者是否要等待;只有当值为true时,连接池设置的maxWaitMillis才会生效
poolConfig.setBlockWhenExhausted(CompositeAppConfigProperties.getInstance().boolValue("redis.pool.blockWhenExhausted", true));
return poolConfig;
}
public static void doMonitor() {
Map storesMap = RedisStore.presentAll();
if (Maps.isEmpty(storesMap)) {
return;
}
for (Map.Entry it : storesMap.entrySet()) {
RedisStore instance = it.getValue();
if (null == instance || Objects.isAnyNull(instance.getJedisPoolConfig(), instance.getJedisPool())) {
continue;
}
if (AppBootConstants.isLoggerEnabled("logger.switch.jedis") && log.isInfoEnabled()) {
String format = "RedisStore instance={} {}JedisPoolConfig: {} {}JedisPoolStats: {}{}";
Map configMap = buildPoolConfigMap(instance.getJedisPoolConfig());
GenericObjectPool> internalPool = (GenericObjectPool>) Reflections.getFieldValue(instance.getJedisPool(), "internalPool");
Map statsMap = buildPoolStatsMap(internalPool);
log.info(format, instance.getName(), Environments.LINE_SEPARATER,
JSON.toJSONString(configMap), Environments.LINE_SEPARATER,
JSON.toJSONString(statsMap), Environments.LINE_SEPARATER);
}
}
}
static Map buildPoolConfigMap(JedisPoolConfig jedisPoolConfig) {
if (null == jedisPoolConfig || Strings.isBlank(jedisPoolConfig.toString())) {
return Maps.newHashMap();
}
String txt = jedisPoolConfig.toString();
if (txt.endsWith("]") && txt.startsWith("[")) {
txt = txt.substring(1, txt.length() - 1).trim();
}
txt = Strings.substringsBetween(txt, "[", "]")[0];
return Maps.parseMap(txt, ",");
}
static Map buildPoolStatsMap(GenericObjectPool> pool) {
return Maps.createMap(
"isClosed", pool.isClosed(),
"activeNum", pool.getNumActive(),
"idleNum", pool.getNumIdle(),
"waitersNum", pool.getNumWaiters(),
"createdCount", pool.getCreatedCount(),
"borrowedCount", pool.getBorrowedCount(),
"returnedCount", pool.getReturnedCount(),
"destroyedCount", pool.getDestroyedCount(),
"destroyedByEvictorCount", pool.getDestroyedByEvictorCount(),
"destroyedByBorrowValidationCount", pool.getDestroyedByBorrowValidationCount()
);
}
static void warnLog(Object[] params) {
warnTimes++;
if (warnTimes <= 10) {
log.warn("!!! No suitable redisConfig for {}: [host={}, port={}, db={}]", params);
}
if (warnTimes > (Integer.MAX_VALUE - 50000)) {
warnTimes = 20000;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy