pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xyz.haijin</groupId>
<artifactId>redis-test</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version> <!-- 使用最新的Spring Boot 3版本 -->
<relativePath/>
</parent>
<properties>
<java.version>17</java.version> <!-- Spring Boot 3需要Java 17+ -->
<jedis.version>5.0.2</jedis.version>
<commons-pool2.version>2.11.1</commons-pool2.version>
</properties>
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter for Redis (排除默认的Lettuce) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Jedis Redis Client -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<!-- Apache Commons Pool 2 (Jedis依赖) -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${commons-pool2.version}</version>
</dependency>
<!-- JSON序列化支持 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Lombok (可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>22.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml:
spring:
redis:
host: 192.168.3.10 # Redis服务器地址
port: 6379 # Redis服务器端口
password: 123456 # Redis密码,没有密码留空
timeout: 2000 # 连接超时时间(毫秒)
database: 0 # 使用的数据库索引(0-15)
# Jedis连接池配置
jedis:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
# 高级配置(需要与您的JedisConfig类匹配)
# 以下配置需要自定义属性绑定,标准spring.redis不直接支持
test-on-borrow: false # 在获取连接时检查连接有效性
test-on-return: false # 在归还连接时检查连接有效性
RedisHashVo:
package xyz.haijin.vo;
import redis.clients.jedis.Response;
/**
* 2025/5/25.
*
* @author haijin
*/
public class RedisHashVo {
private String key;
private String field;
private String value;
private Response<String> response;
public RedisHashVo() {
}
public RedisHashVo(String key, String field) {
this.key = key;
this.field = field;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Response<String> getResponse() {
return response;
}
public void setResponse(Response<String> response) {
this.response = response;
}
}
RedisUtil:
package xyz.haijin.utils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtil {
private final RedisTemplate<String, Object> redisTemplate;
public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
// ==============================common============================
/**
* 指定缓存失效时间
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 获取过期时间
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
/**
* 普通缓存获取
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
JedisPoolManager:
package xyz.haijin.utils;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
import java.util.List;
/**
* 2025/5/25.
*
* @author haijin
*/
@Slf4j
public class JedisPoolManager {
private static final ThreadLocal<JedisPool> CURRENT_JEDIS_POOL = new ThreadLocal<JedisPool>();
private List<JedisPool> jedisPools;
public Jedis getJedis() {
for (int i = 0, size = jedisPools.size(); i < size; i++) {
JedisPool jedisPool = jedisPools.get(i);
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
if (jedis.isConnected()) {
CURRENT_JEDIS_POOL.set(jedisPool);
return jedis;
} else {
jedis.close();
log.error("Get jedis connection from pool but not connected.");
}
} catch (JedisConnectionException e) {
log.error("Get jedis connection from pool list index:{}", i, e);
if (jedis != null) {
log.warn("Return broken resource:" + jedis);
log.info("jedis close bef");
jedis.close();
}
}
}
return null;
}
public void setJedisPools(List<JedisPool> jedisPools) {
this.jedisPools = jedisPools;
}
}
JedisService:
RedisDataAccessException:
package xyz.haijin.exception;
import org.springframework.dao.DataAccessException;
/**
* 2025/5/25.
*
* @author haijin
*/
public class RedisDataAccessException extends DataAccessException {
public RedisDataAccessException(String message) {
super(message);
}
public RedisDataAccessException(String message, Throwable cause) {
super(message, cause);
}
}
JedisConfig:
package xyz.haijin.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
/**
* Jedis 客户端配置类
* 用于配置Redis连接参数和连接池参数
*/
public class JedisConfig {
/**
* Redis服务器主机地址
* 默认值: localhost
* 示例: 192.168.1.100
*/
private String host;
/**
* Redis服务器端口号
* 默认值: 6379
*/
private int port;
/**
* 连接超时时间(毫秒)
* 建议值: 2000-5000ms
* 0表示无超时限制(不推荐)
*/
private int timeout;
/**
* 连接池最大连接数
* 建议值: 根据业务QPS调整(通常为QPS/1000 * 2)
* 默认值: 8
* -1表示无限制(不推荐)
*/
private int maxTotal;
/**
* 连接池中最大空闲连接数
* 建议值: maxTotal的50-70%
* 默认值: 8
*/
private int maxIdle;
/**
* 获取连接时的最大等待时间(毫秒)
* 建议值: 1000-3000ms
* 默认值: -1 (无限等待,不推荐)
*/
private long maxWait;
/**
* 连接池中最小空闲连接数
* 建议值: 根据业务低谷期流量设置
* 默认值: 0
*/
private int minIdle;
/**
* Redis服务器密码
* 注意: 生产环境必须设置
* 格式:
* - 无密码: null或空字符串
* - 有密码: 实际密码字符串
*/
private String password;
/**
* 从连接池获取连接时是否校验连接有效性
* 开启后会降低性能但能避免拿到失效连接
* 建议值: 生产环境true,开发环境false
*/
private boolean testOnBorrow;
/**
* 归还连接到连接池时是否校验连接有效性
* 开启后会降低性能但能保证连接池中连接可用
* 建议值: 生产环境true,开发环境false
*/
private boolean testOnReturn;
}
RedisAutoConfiguration:
package xyz.haijin.autoconfigure;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import xyz.haijin.config.JedisConfig;
import xyz.haijin.utils.JedisPoolManager;
import java.util.Collections;
/**
* 2025/5/25.
*
* @author haijin
*/
@Configuration
@DependsOn("jedisConfig")
@ConditionalOnClass({Jedis.class})
public class RedisAutoConfiguration {
@Autowired
private JedisConfig redisConfig;
@Bean("writeJedisPoolManager")
public JedisPoolManager writeJedisPoolManager() {
JedisPoolManager jedisPoolManager = new JedisPoolManager();
jedisPoolManager.setJedisPools(Collections.singletonList(this.writeJedisPoolMaster()));
return jedisPoolManager;
}
@Bean("readJedisPoolManager")
public JedisPoolManager readJedisPoolManager() {
JedisPoolManager jedisPoolManager = new JedisPoolManager();
jedisPoolManager.setJedisPools(Collections.singletonList(this.readJedisPoolMaster()));
return jedisPoolManager;
}
private JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(this.redisConfig.getMaxIdle());
config.setMaxTotal(this.redisConfig.getMaxTotal());
config.setMaxWaitMillis(this.redisConfig.getMaxWait());
config.setMinIdle(this.redisConfig.getMinIdle());
config.setTestOnReturn(this.redisConfig.isTestOnReturn());
config.setTestOnBorrow(this.redisConfig.isTestOnBorrow());
return config;
}
private JedisPool writeJedisPoolMaster() {
return new JedisPool(this.jedisPoolConfig(), this.redisConfig.getHost(), this.redisConfig.getPort(), this.redisConfig.getTimeout(), this.redisConfig.getPassword());
}
private JedisPool readJedisPoolMaster() {
return new JedisPool(this.jedisPoolConfig(), this.redisConfig.getHost(), this.redisConfig.getPort(), this.redisConfig.getTimeout(), this.redisConfig.getPassword());
}
}