@Component
public class RedisTemplateUtil {
private static final Logger logger = LoggerFactory.getLogger(RedisTemplateUtil.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 写入缓存
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, String value) {
boolean result = false;
try {
redisTemplate.opsForValue().set(key, value);
result = true;
} catch (Exception e) {
logger.error("RedisTemplateUtil.set error: ", e);
}
return result;
}
/**
* 写入缓存设置时效时间
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, String value, Long expireTime) {
boolean result = false;
try {
redisTemplate.opsForValue().set(key, value,expireTime, TimeUnit.SECONDS);
// redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
logger.error("RedisTemplateUtil.set error: ", e);
}
return result;
}
/**
* 批量删除对应的value
*
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key
*
* @param pattern
*/
public void removePattern(final String pattern) {
Set<String> keys = redisTemplate.keys(pattern);
if (keys.size() > 0) {
redisTemplate.delete(keys);
}
}
/**
* 删除对应的value
*
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
*
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
*
* @param key
* @return
*/
public String get(final String key) {
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
String result = (String) operations.get(key);
return result;
}
/**
* 将一个值插入到列表头部
*
* @param k
* @param v
*/
public <T> void lPush(String k, T v) {
redisTemplate.opsForList().leftPush(k, v);
}
/**
* 将一个值插入到列表的尾部(最右边)
*
* @param key
* @param value
*/
public <T> void rPush(String key, T value) {
redisTemplate.opsForList().rightPush(key, value);
}
/**
* 将多个值插入到列表头部
*
* @param k
* @param v
*/
public <T> void lPushAll(String k, Collection<T> v) {
redisTemplate.opsForList().leftPushAll(k, v);
}
/**
* 将多个值插入到列表的尾部(最右边)
*
* @param key
* @param value
*/
public void rPushAll(String key, Object... values) {
redisTemplate.opsForList().rightPushAll(key, values);
}
/**
* 返回列表中指定区间内的元素,区间以偏移量 start 和 end 指定
* @param k
* @param start
* @param end
* @return
*/
public <T> List<T> lRange(String k, long start, long end) {
ListOperations<String, T> list = (ListOperations<String, T>) redisTemplate.opsForList();
return list.range(k, start, end);
}
/**
* 往集合Set中添加元素
* @param k
* @param v
* @return
*/
public boolean sadd(String k, Object... v){
boolean flag = false;
try {
redisTemplate.opsForSet().add(k, v);
flag = true;
} catch (Exception e) {
logger.error("RedisTemplateUtil.sadd error: ", e);
}
return flag;
}
/**
* 判断成员元素是否是集合Set的成员
* @param k
* @param v
* @return
*/
public boolean sismember(String k, Object v){
boolean flag = false;
try {
flag = redisTemplate.opsForSet().isMember(k, v);
} catch (Exception e) {
logger.error("RedisTemplateUtil.sismember error: ", e);
}
return flag;
}
public boolean sismember2(String k, Object v){
return redisTemplate.opsForSet().isMember(k, v);
}
/**
* 读取缓存
*
* @param key
* @return
*/
public Object genValue(final String key) {
Object result = null;
ValueOperations<String, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 将一个成员元素及其分数值加入到有序集当中
* @param key
* @param member
* @param score
* @return
*/
public boolean zadd(String key, Object member, double score){
boolean flag = false;
try {
redisTemplate.opsForZSet().add(key, member, score);
flag = true;
} catch (Exception e) {
logger.error("RedisTemplateUtil.zadd error: ", e);
}
return flag;
}
/**
* 返回有序集中,成员的分数值
* @param key
* @param member
* @return
*/
public Double zscore(String key, Object member) {
return redisTemplate.opsForZSet().score(key, member);
}
/**
* 移除有序集中的一个或多个成员
* @param key
* @param member
* @return
*/
public void zrem(String key, Object... member) {
redisTemplate.opsForZSet().remove(key, member);
}
/**
* 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大)次序排列
* @param key
* @param min
* @param max
* @return
*/
public Set<Object> zrangeByScore(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
}
/**
* 返回有序集中,指定区间内的成员。其中成员的位置按分数值递增(从小到大)来排序
* @param key
* @param start
* @param end
* @return
*/
public Set<Object> zrange(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
/**
* 如果key存在,写入缓存并设置时效时间;false:key已存在,true:写入成功
* @param key
* @param value
* @param expireTime 单位:秒
* @return
*/
public boolean setIfAbsent(final String key, String value, Long expireTime) {
boolean result = false;
try {
result = redisTemplate.opsForValue().setIfAbsent(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
} catch (Exception e) {
logger.error("RedisTemplateUtil.setnx error: ", e);
}
return result;
}
}
用代码配置redis信息
先准备实体类
@ConfigurationProperties(prefix = “spring.redis.cluster”)
@Component
public class RedisProperties {
private Integer database;
private String nodes;
private Integer connectTimeout;
private Integer readTimeout;
private Integer maxRedirects;
private Integer maxTotal;
private Integer maxWaitMillis;
private Integer maxIdle;
private Integer minIdle;
private boolean testOnBorrow;
private String password;
public String getNodes() {
return nodes;
}
public void setNodes(String nodes) {
this.nodes = nodes;
}
public Integer getMaxRedirects() {
return maxRedirects;
}
public void setMaxRedirects(Integer maxRedirects) {
this.maxRedirects = maxRedirects;
}
public Integer getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(Integer maxIdle) {
this.maxIdle = maxIdle;
}
public Integer getMinIdle() {
return minIdle;
}
public void setMinIdle(Integer minIdle) {
this.minIdle = minIdle;
}
public boolean isTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public Integer getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(Integer maxTotal) {
this.maxTotal = maxTotal;
}
public Integer getMaxWaitMillis() {
return maxWaitMillis;
}
public void setMaxWaitMillis(Integer maxWaitMillis) {
this.maxWaitMillis = maxWaitMillis;
}
public Integer getDatabase() {
return database;
}
public void setDatabase(Integer database) {
this.database = database;
}
public Integer getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Integer getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(Integer readTimeout) {
this.readTimeout = readTimeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
redis链接信息处理
@Configuration
//@ConditionalOnClass(JedisCluster.class)
public class RedisConfig {
private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);
@Resource
private RedisProperties redisProperties;
/**
* 配置 Redis 连接池信息
*/
@Bean
public JedisPoolConfig getJedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(redisProperties.getMaxTotal());
jedisPoolConfig.setMaxWaitMillis(redisProperties.getMaxWaitMillis());
jedisPoolConfig.setMaxIdle(redisProperties.getMaxIdle());
jedisPoolConfig.setMinIdle(redisProperties.getMinIdle());
jedisPoolConfig.setTestOnBorrow(redisProperties.isTestOnBorrow());
return jedisPoolConfig;
}
/**
* 配置 Redis 连接工厂
* @param jedisPoolConfig
* @return
*/
@Bean
public JedisConnectionFactory getJedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
logger.info("redis配置信息:nodes={}", redisProperties.getNodes());
JedisConnectionFactory jedisConnectionFactory = null;
JedisClientConfiguration.JedisClientConfigurationBuilder builder = JedisClientConfiguration.builder();
builder.usePooling().poolConfig(jedisPoolConfig);
builder.connectTimeout(Duration.ofMillis(redisProperties.getConnectTimeout()));
builder.readTimeout(Duration.ofMillis(redisProperties.getReadTimeout()));
JedisClientConfiguration jedisClientConfiguration = builder.build();
String[] cNodes = redisProperties.getNodes().split(",");
// 大于1,集群配置,否则单实例
if(cNodes.length > 1){
// 分割出集群节点
List<RedisNode> nodeList = new ArrayList<>();
for (String node : cNodes) {
String[] hp = node.split(":");
nodeList.add(new RedisNode(hp[0], Integer.parseInt(hp[1])));
}
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
redisClusterConfiguration.setClusterNodes(nodeList);
redisClusterConfiguration.setMaxRedirects(redisProperties.getMaxRedirects());
if(StringUtils.isNotBlank(redisProperties.getPassword())){
redisClusterConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
}
jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisClientConfiguration);
jedisConnectionFactory.getStandaloneConfiguration().setDatabase(redisProperties.getDatabase());
}else{
// 分割出IP和PORT
String[] hp = cNodes[0].split(":");
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(hp[0]);
redisStandaloneConfiguration.setPort(Integer.parseInt(hp[1]));
redisStandaloneConfiguration.setDatabase(redisProperties.getDatabase());
if(StringUtils.isNotBlank(redisProperties.getPassword())){
redisStandaloneConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
}
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
}
return jedisConnectionFactory;
}
/**
* 设置数据存入redis 的序列化方式 redisTemplate序列化默认使用的jdkSerializeable
* 存储二进制字节码,导致key会出现乱码,所以自定义序列化类
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
logger.info("初始RedisTemplate Bean,修改默认序列化方式");
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedissonClient redisson() {
Config config = null;
String[] nodes = this.convert(Arrays.asList(this.redisProperties.getNodes().split(",")));
config = new Config();
((ClusterServersConfig) config.useClusterServers()
.addNodeAddress(nodes)
.setConnectTimeout(this.redisProperties.getConnectTimeout()))
.setReadMode(ReadMode.MASTER_SLAVE)
.setPassword(this.redisProperties.getPassword());
return Redisson.create(config);
}
private String[] convert(List<String> nodesObject) {
List<String> nodes = new ArrayList(nodesObject.size());
Iterator var3 = nodesObject.iterator();
while(true) {
while(var3.hasNext()) {
String node = (String)var3.next();
if (!node.startsWith("redis://") && !node.startsWith("rediss://")) {
nodes.add("redis://" + node);
} else {
nodes.add(node);
}
}
return (String[])nodes.toArray(new String[nodes.size()]);
}
}
}
Jedis 用作来做分布式锁
@Component
public class JedisDistributedLock {
private final Logger logger = LoggerFactory.getLogger(JedisDistributedLock.class);
private static String LOCK_PREFIX = "JedisDistributedLock_";
private static final long LOCK_EXPIRE = 60000;
private DefaultRedisScript<Boolean> lockScript;
@Resource
private RedisTemplate<Object, Object> redisTemplate;
public static final String UNLOCK_LUA;
static {
StringBuilder sb = new StringBuilder();
sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
sb.append("then ");
sb.append(" return redis.call(\"del\",KEYS[1]) ");
sb.append("else ");
sb.append(" return 0 ");
sb.append("end ");
UNLOCK_LUA = sb.toString();
}
public boolean setLock(String key, long expire) {
try {
Boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.set(key.getBytes(), getHostIp().getBytes(), Expiration.seconds(expire) ,RedisStringCommands.SetOption.ifAbsent());
}
});
return result;
} catch (Exception e) {
logger.error("set redis occured an exception", e);
}
return false;
}
/**
* 删除锁
*
* @param key
*/
public void delete(String key) {
redisTemplate.delete(key);
}
public String get(String key) {
try {
RedisCallback<String> callback = (connection) -> {
JedisCommands commands = (JedisCommands) connection.getNativeConnection();
return commands.get(key);
};
String result = redisTemplate.execute(callback);
return result;
} catch (Exception e) {
logger.error("get redis occured an exception", e);
}
return "";
}
/**
* 释放锁操作
* @param key
* @param value
* @return
*/
private boolean releaseLock(String key, String value) {
lockScript = new DefaultRedisScript<Boolean>();
lockScript.setScriptSource(
new ResourceScriptSource(new ClassPathResource("unlock.lua")));
lockScript.setResultType(Boolean.class);
// 封装参数
List<Object> keyList = new ArrayList<Object>();
keyList.add(key);
keyList.add(value);
Boolean result = (Boolean) redisTemplate.execute(lockScript, keyList);
return result;
}
/**
* 获取本机内网IP地址方法
*
* @return
*/
private static String getHostIp() {
try {
Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
while (allNetInterfaces.hasMoreElements()) {
NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress ip = (InetAddress) addresses.nextElement();
if (ip != null
&& ip instanceof Inet4Address
&& !ip.isLoopbackAddress() //loopback地址即本机地址,IPv4的loopback范围是127.0.0.0 ~ 127.255.255.255
&& ip.getHostAddress().indexOf(":") == -1) {
return ip.getHostAddress();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisLockHelper {
private static final String DELIMITER = "|";
/**
* 如果要求比较高可以通过注入的方式分配
*/
private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newScheduledThreadPool(10);
private RedisTemplate<String, Object> redisTemplate;
public RedisLockHelper(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 获取锁(存在死锁风险)
*
* @param lockKey
* lockKey
* @param value
* value
* @param time
* 超时时间
* @param unit
* 过期单位
* @return true or false
*/
public boolean tryLock(final String lockKey, final String value, final long time, final TimeUnit unit) {
return redisTemplate.execute((RedisCallback<Boolean>) connection -> connection.set(lockKey.getBytes(),
value.getBytes(), Expiration.from(time, unit), RedisStringCommands.SetOption.SET_IF_ABSENT));
}
/**
* 获取锁
*
* @param lockKey
* lockKey
* @param uuid
* UUID
* @param timeout
* 超时时间
* @param unit
* 过期单位
* @return true or false
*/
public boolean lock(String lockKey, final String uuid, long timeout, final TimeUnit unit) {
final long milliseconds = Expiration.from(timeout, unit).getExpirationTimeInMilliseconds();
final String expiresStr = (System.currentTimeMillis() + milliseconds) + DELIMITER + uuid;
boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey, expiresStr);
if (success) {
redisTemplate.expire(lockKey, timeout, TimeUnit.SECONDS);
return true;
}
String currentValue = (String) redisTemplate.opsForValue().get(lockKey);
if(StringUtils.isNotEmpty(currentValue) && Long.parseLong(currentValue.split(Pattern.quote(DELIMITER))[0]) < System.currentTimeMillis()){
String oldVal = (String) redisTemplate.opsForValue().getAndSet(lockKey, expiresStr);
if(StringUtils.isNotEmpty(oldVal) && oldVal.equals(currentValue) ){
return true;
}
}
return false;
}
public void unlock(String lockKey, String value) {
unlock(lockKey, value, 0, TimeUnit.MILLISECONDS);
}
/**
* 延迟unlock
*
* @param lockKey
* key
* @param uuid
* client(最好是唯一键的)
* @param delayTime
* 延迟时间
* @param unit
* 时间单位
*/
public void unlock(final String lockKey, final String uuid, long delayTime, TimeUnit unit) {
if (StringUtils.isEmpty(lockKey)) {
return;
}
if (delayTime <= 0) {
doUnlock(lockKey, uuid);
} else {
EXECUTOR_SERVICE.schedule(() -> doUnlock(lockKey, uuid), delayTime, unit);
}
}
/**
* @param lockKey
* key
* @param uuid
* client(最好是唯一键的)
*/
private void doUnlock(final String lockKey, final String uuid) {
String val = (String) redisTemplate.opsForValue().get(lockKey);
if(val == null){
return;
}
final String[] values = val.split(Pattern.quote(DELIMITER));
if (values.length <= 0) {
return;
}
if (uuid.equals(values[1])) {
redisTemplate.delete(lockKey);
}
}
}