我负责的项目中用到了redis,因为是单人负责整个项目,所以只能去网上找相关的资料和文档,现在项目上线,将相关配置记录下,方便自己以后查阅,也希望能给其他同学带来参考和帮助。
springBoot2.0以后版本做了重大更新,本博客基于的是1.5.10版本,不适用于2.0以上的版本,所以请大家注意下。jdk版本是1.8,redis集群是公司运维的同学搭建的,所以在此不讨论redis集群的版本号和配置问题。
首先先引入相关的pom配置,官方提供了redis集群的配置,所以不需要做过多的引入:
org.springframework.boot
spring-boot-starter-data-redis
1.5.10.RELEASE
version版本号可以自定义,也可以根据你的springBoot版本走,这里是为了给大家看的清楚,写死了版本号
然后是redis的配置文件:
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
/**
* ClassName: JedisClusterConfig
* Description:
* @date 2018年4月3日
*/
@Configuration
public class JedisClusterConfig {
private static final Logger log = LoggerFactory.getLogger(JedisClusterConfig.class);
@Value("${redis.nodes}")
private String nodes;
@Value("${redis.commandTimeout}")
private int commandTimeout;
@Value("${redis.pwd}")
private String pwd;
@Value("${redis.maxTotal}")
private int maxTotal;
@Value("${redis.maxIdle}")
private int maxIdle;
@Value("${redis.minIdle}")
private int minIdle;
@Value("${redis.maxWait}")
private int maxWait;
/**
* 注意:
* 这里返回的JedisCluster是单例的,并且可以直接注入到其他类中去使用
* @return
*/
@Bean
public JedisCluster getJedisCluster() {
log.info("进入redis集群初始化方法:访问集群地址为:"+nodes);
String[] serverArray = nodes.split(",");//获取服务器数组(这里要相信自己的输入,所以没有考虑空指针问题)
Set nodes = new HashSet<>();
for (String ipPort : serverArray) {
String[] ipPortPair = ipPort.split(":");
nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim())));
}
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);//设置最小空闲数
config.setMaxWaitMillis(maxWait);
//在获取Jedis连接时,自动检验连接是否可用
config.setTestOnBorrow(true);
//在将连接放回池中前,自动检验连接是否有效
config.setTestOnReturn(true);
//自动测试池中的空闲连接是否都是可用连接
config.setTestWhileIdle(true);
//连接耗尽时是否阻塞, false报异常,ture阻塞直到超时,默认true
config.setBlockWhenExhausted(false);
//表示idle object evitor两次扫描之间要sleep的毫秒数
config.setTimeBetweenEvictionRunsMillis(30000);
//表示idle object evitor每次扫描的最多的对象数
config.setNumTestsPerEvictionRun(10);
//表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
config.setMinEvictableIdleTimeMillis(60000);
//需要密码连接的创建对象方式
//参数依次是:集群地址,链接超时时间,返回值的超时时间,链接尝试次数,密码和配置文件
return new JedisCluster(nodes,commandTimeout,10000,3,pwd,config);
}
}
这里提供的是最全的JedisCluster实例化方法,所有的参数都传入,如果你并不需要传入这么多参数,JedisCluster还提供了其他方法,包括集群的和单点的都有,可以根据需求自己配置:
public JedisCluster(HostAndPort node) {
this(Collections.singleton(node), DEFAULT_TIMEOUT);
}
public JedisCluster(HostAndPort node, int timeout) {
this(Collections.singleton(node), timeout, DEFAULT_MAX_REDIRECTIONS);
}
public JedisCluster(HostAndPort node, int timeout, int maxAttempts) {
this(Collections.singleton(node), timeout, maxAttempts, new GenericObjectPoolConfig());
}
public JedisCluster(HostAndPort node, final GenericObjectPoolConfig poolConfig) {
this(Collections.singleton(node), DEFAULT_TIMEOUT, DEFAULT_MAX_REDIRECTIONS, poolConfig);
}
public JedisCluster(HostAndPort node, int timeout, final GenericObjectPoolConfig poolConfig) {
this(Collections.singleton(node), timeout, DEFAULT_MAX_REDIRECTIONS, poolConfig);
}
public JedisCluster(HostAndPort node, int timeout, int maxAttempts,
final GenericObjectPoolConfig poolConfig) {
this(Collections.singleton(node), timeout, maxAttempts, poolConfig);
}
public JedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
int maxAttempts, final GenericObjectPoolConfig poolConfig) {
super(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, poolConfig);
}
public JedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
int maxAttempts, String password, final GenericObjectPoolConfig poolConfig) {
super(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, password, poolConfig);
}
public JedisCluster(Set nodes) {
this(nodes, DEFAULT_TIMEOUT);
}
public JedisCluster(Set nodes, int timeout) {
this(nodes, timeout, DEFAULT_MAX_REDIRECTIONS);
}
public JedisCluster(Set nodes, int timeout, int maxAttempts) {
this(nodes, timeout, maxAttempts, new GenericObjectPoolConfig());
}
public JedisCluster(Set nodes, final GenericObjectPoolConfig poolConfig) {
this(nodes, DEFAULT_TIMEOUT, DEFAULT_MAX_REDIRECTIONS, poolConfig);
}
public JedisCluster(Set nodes, int timeout, final GenericObjectPoolConfig poolConfig) {
this(nodes, timeout, DEFAULT_MAX_REDIRECTIONS, poolConfig);
}
public JedisCluster(Set jedisClusterNode, int timeout, int maxAttempts,
final GenericObjectPoolConfig poolConfig) {
super(jedisClusterNode, timeout, maxAttempts, poolConfig);
}
public JedisCluster(Set jedisClusterNode, int connectionTimeout, int soTimeout,
int maxAttempts, final GenericObjectPoolConfig poolConfig) {
super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, poolConfig);
}
public JedisCluster(Set jedisClusterNode, int connectionTimeout, int soTimeout,
int maxAttempts, String password, final GenericObjectPoolConfig poolConfig) {
super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, poolConfig);
}
redis的配置文件也很简单,因为没找到redis官方的写法,所以就按照网上的写法自定义了yml注解,直接用@Value("${redis.maxIdle}")注入,也可用@ConfigurationProperties直接将参数注入到一个对象中。下面是我的yml写法,给大家提供下参考:
redis:
nodes: 10.200.200.2:7011,10.200.200.2:7012,10.200.200.2:7013,10.200.200.2:7014,10.200.200.2:7015,10.200.200.2:7016
commandTimeout: 10000 #redis操作的超时时间
maxTotal: 5000 #最大连接数
maxIdle: 30 #最大空闲连接数
minIdle: 5 #最小空闲连接数
maxWait: 3000 #获取连接最大等待时间 ms #default -1
pwd:
因为是自定义配置,所以所有需要多环境配置的参数都可以写过来,方便部署,而redis集群的使用就更加简单了,下面是根据网上的配置自己写的util:
/**
* ClassName: RedisUtil
* Description:
* @date 2018年4月3日
*/
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;
@Component
public class RedisUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);
@Autowired
private JedisCluster jedisCluster;
/**
* 设置缓存
* @param key 缓存key
* @param value 缓存value
*/
public void set(String key, String value) {
jedisCluster.set(key, value);
LOGGER.debug("RedisUtil:set cache key={},value={}", key, value);
}
/**
* 设置缓存对象
* @param key 缓存key
* @param obj 缓存value
*/
public void setObject(String key, T obj , int expireTime) {
jedisCluster.setex(key, expireTime, JSON.toJSONString(obj));
}
/**
* 获取指定key的缓存
* @param key---JSON.parseObject(value, User.class);
*/
public String getObject(String key) {
return jedisCluster.get(key);
}
/**
* 判断当前key值 是否存在
*
* @param key
*/
public boolean hasKey(String key) {
return jedisCluster.exists(key);
}
/**
* 设置缓存,并且自己指定过期时间
* @param key
* @param value
* @param expireTime 过期时间
*/
public void setWithExpireTime( String key, String value, int expireTime) {
jedisCluster.setex(key, expireTime, value);
LOGGER.debug("RedisUtil:setWithExpireTime cache key={},value={},expireTime={}", key, value, expireTime);
}
/**
* 获取指定key的缓存
* @param key
*/
public String get(String key) {
String value = jedisCluster.get(key);
LOGGER.debug("RedisUtil:get cache key={},value={}",key, value);
return value;
}
/**
* 删除指定key的缓存
* @param key
*/
public void delete(String from,String key) {
jedisCluster.del(key);
LOGGER.info("RedisUtil:delete "+from+" cache key={}", key);
}
/**
* @Title: expire
* @Description: 更新key的失效时间
* @param key
* @throws
*/
public Long expire(String key,int seconds) {
LOGGER.debug("RedisUtil:expire cache key={}", key);
return jedisCluster.expire(key, seconds);
}
public Long pexpire(String key,long seconds) {
LOGGER.debug("RedisUtil:expire cache key={}", key);
return jedisCluster.pexpire(key, seconds);
}
}
这个工具类没有过多封装只是打印了log,实际使用中可以根据情况直接注入JedisCluster对象,也可以将各种判断,序列化引入,封装的更完善。上述写法亲测有效,如果在使用中发现其他问题,可以留言,大家一起探讨。