转载

JAVA缓存-Redis入门级使用

#前言

Java 缓存实现方案有很多,最基本的自己使用 Map 去构建缓存,再高级点的使用 Ehcache 或者 Goolgeguava 作为内存缓存框架, Ehcache 可以满足单机缓存的需求( Ehcache 的具体使用在我过往的文章中有所介绍),如果我们是多台机子共用缓存数据的话, Ehcache 可通过 rmijgroupjms 的方式实现,但是实用性与操作性不高且复杂,现时大部分应用仅用 Ehcache 作为单机缓存使用,这时候我们可以通过搭建缓存服务器解决多机使用的问题,常见的缓存服务器有 MemcachedRedis 等。

现时业界主流大多使用 Redis 。所以本文主要介绍在 Java 中如何使用 Redis 。至于如何搭建 Redis ,我在过往的文章中已有所介绍,不知道如何搭建的同学,可以参考我过往的文章,下文所用到相关的 Redis 信息均为搭建教程中的信息。

PS:文章中所用到的示例代码,部分参考至开源项目iBase4J,特此声明。

本文同步发布于简书 : www.jianshu.com/p/5a9946870…

Java连接Redis

Java 连接 Redis 官方推荐的是使用 JedisRedisson 进行连接操作, SpringRedis 有很好的支持,所以此文我结合 Spring 中的 Spring DataRedis 进行操作。

1. maven引用

<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring-data-redis</artifactId>
	<version>1.8.7.RELEASE</version>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>2.9.0</version>
</dependency>
<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson</artifactId>
	<version>3.5.5</version>
</dependency>
复制代码

2. 建立Redis配置文件

classpath 下建立Redis配置文件 redis.properties

如果同学们是搭建 Redis 高可用架构,是通过向外提供 VIP 虚拟IP的方式连接 Redis ,则只需在配置文件中将 redis.host=172.16.2.185 单机IP改为 VIP 虚拟IP redis.host=172.16.2.250 即可实现 Redis 高可用,而不需要使用 Spring 提供的 RedisSentinel 方案实现 Redis 高可用。

#VIP
#redis.host=172.16.2.250
redis.host=172.16.2.185
redis.port=6379
redis.password=123456
#最小空闲数
redis.minIdle=2
#最大空闲数
redis.maxIdle=10
#最大连接数
redis.maxTotal=1000
#最大建立连接等待时间
redis.maxWaitMillis=3000
#客户端超时时间单位是毫秒
redis.timeout=120000
#明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个  
redis.testOnBorrow=true
redis.expiration=600
复制代码

3. 与Spring结合

3.1 配置Jedis实现

classpath 下建立文件夹 spring 用于存放所有与 spring 相关的配置文件。在 spring 文件夹下建立 spring-redis.xml ,主要用于注入 Jedis

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"
>
	<context:property-placeholder location="classpath*:redis.properties" ignore-unresolvable="true"/>
	
	<!-- jedis 配置-->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" >
        <!--最小空闲数-->  
        <property name="minIdle" value="${redis.minIdle}" />
        <!--最大空闲数-->  
        <property name="maxIdle" value="${redis.maxIdle}" />
        <!--最大连接数-->  
        <property name="maxTotal" value="${redis.maxTotal}" />
        <!--最大建立连接等待时间-->  
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个-->  
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
    </bean >
		
	<!-- redis服务器中心 -->
	<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
      <property name="poolConfig" ref="jedisPoolConfig"/>
      <property name="port" value="${redis.port}"/>
      <property name="hostName" value="${redis.host}"/>
      <property name="password" value="${redis.password}"/>
      <property name="timeout" value="${redis.timeout}" />
  </bean>
	<!-- 缓存序列化方式 -->
	<bean id="keySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
	
	<bean id="valueSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
	
	<!-- 缓存 -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="connectionFactory" ref="jedisConnectionFactory" />
		<property name="enableTransactionSupport" value="true" />
		<property name="keySerializer" ref="keySerializer" />
		<property name="valueSerializer" ref="valueSerializer" />
		<property name="hashKeySerializer" ref="keySerializer" />
		<property name="hashValueSerializer" ref="valueSerializer" />
	</bean>
	
	<bean class="com.easylink.mall.core.cache.redis.RedisHelper" >
		<property name="redisTemplate" ref="redisTemplate" />
	</bean>
	<!-- 缓存管理 -->
	<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
		<constructor-arg index="0" ref="redisTemplate" />
		<property name="transactionAware" value="true" />
		<property name="defaultExpiration" value="${redis.expiration}" />
	</bean>
</beans>
复制代码

3.2 配置Redisson实现

spring 文件夹下建立 spring-redisson.xml ,主要用于注入 Redisson

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"
>
	<context:property-placeholder location="classpath*:redis.properties" ignore-unresolvable="true"/>
	
	<!-- redisson 配置-->
	<bean id="redissonClient" class="com.easylink.mall.core.cache.redisson.Client" init-method="init">
		<property name="password" value="${redis.password}" />
		<!-- SingleServer -->
		<property name="address" value="redis://${redis.host}:${redis.port}" />
		<!-- ClusterServers -->
		<!-- <property name="nodeAddresses" value="${redis.cluster}}" /> -->
		<!-- MasterSlaveServers -->
		<!-- <property name="masterAddress" value="${redis.master}" />
		<property name="slaveAddresses" value="${redis.slave}" /> -->
	</bean>
	
	<!-- redisson 工具类 -->
	<bean class="com.easylink.mall.core.cache.redisson.RedissonHelper">
		<property name="redissonClient" ref="redissonClient" />
	</bean>
</beans>
复制代码

4. 代码实现

4.1 定义获取缓存的工具类CacheUtil

这个类主要是用于获取缓存管理器,因为 Jedis 封装 Redis 基本操作的接口比较友好,所以基本操作使用 Jedis 实现,但是将 Redis 当做分布式锁使用时,如果是自行用 Jedis 中的setNX + 时间戳过程方法实现的话,会略显复杂,还可能写的不严谨,存在原子性操作或者死锁等问题。此处的分布式锁实现使用 Redisson 帮我们封装好的方法实现加锁与解锁,顺便提一句, Redisson 加锁操作是使用 lua 脚本一次执行加锁与设置过期的操作的,所以不存在原子性问题。这处暂时不展开讨论分布式锁的问题,日后有空再和大家一同探讨分布式锁的问题。

package com.easylink.mall.core.cache.redis;

import com.easylink.mall.core.support.util.PropertiesFileUtil;

public class CacheUtil {
	/**
	 * 缓存管理器,主要执行缓存操作
	 */
	private static CacheManager cacheManager;
	/**
	 * 锁管理器,主要执行加锁与解锁操作
	 */
	private static CacheManager lockManager;

	public static void setCacheManager(CacheManager cacheManager) {
		CacheUtil.cacheManager = cacheManager;
	}

	public static void setLockManager(CacheManager cacheManager) {
		CacheUtil.lockManager = cacheManager;
	}

	public static CacheManager getCache() {
		return cacheManager;
	}

	public static CacheManager getLockManager() {
		return lockManager;
	}

	/** 获取锁 */
	public static boolean tryLock(String key) {
		int expires = 1000 * PropertiesFileUtil.getInstance("redis.properties").getInt("redis.lock.expires", 180);
		return lockManager.setnx(key, expires);
	}

	/** 获取锁 */
	public static boolean getLock(String key) {
		return lockManager.lock(key);
	}

	/** 解锁 */
	public static void unlock(String key) {
		lockManager.unlock(key);
	}
}
复制代码

4.2 定义缓存操作管理接口CacheManager

package com.easylink.mall.core.cache.redis;

import java.io.Serializable;
import java.util.Set;

/**
 * 缓存操作管理接口
 * 
 * @author Ben.
 *
 */
public interface CacheManager {
	/**
	 * 根据key获取对象
	 * 
	 * @param key
	 * @return
	 */
	Object get(final String key);

	/**
	 * 根据正则表达式获取对象
	 * 
	 * @param pattern
	 *            正则表达式
	 * @return
	 */
	Set<Object> getAll(final String pattern);

	/**
	 * 设置key-value
	 * 
	 * @param key
	 * @param value
	 * @param seconds
	 *            过期时间(秒)
	 */
	void set(final String key, final Serializable value, int seconds);

	/**
	 * 设置key-value 过期时间使用默认配置值
	 * 
	 * @param key
	 * @param value
	 */
	void set(final String key, final Serializable value);

	/**
	 * 根据key判断某一对象是否存在
	 * 
	 * @param key
	 * @return 是否存在
	 */
	Boolean exists(final String key);

	/**
	 * 根据key删除对象
	 * 
	 * @param key
	 */
	void del(final String key);

	/**
	 * 根据正则表达式删除对象
	 * 
	 * @param pattern
	 *            正则表达式
	 * @return
	 */
	void delAll(final String pattern);

	/**
	 * 根据key获取对应对象的类型
	 * 
	 * @param key
	 * @return 对应对象的类型
	 */
	String type(final String key);

	/**
	 * 设置key的过期时间
	 * 
	 * @param key
	 * @param seconds
	 * @return 是否设置成功
	 */
	Boolean expire(final String key, final int seconds);

	/**
	 * 设置key在指定时间点后过期
	 * 
	 * @param key
	 * @param unixTime
	 * @return 是否成功
	 */
	Boolean expireAt(final String key, final long unixTime);

	/**
	 * 获取对应key的过期时间
	 * 
	 * @param key
	 * @return
	 */
	Long ttl(final String key);

	/**
	 * 设置新值并返回旧值
	 * 
	 * @param key
	 * @param value
	 * @return 旧值
	 */
	Object getSet(final String key, final Serializable value);

	/**
	 * 对key进行加锁
	 * 
	 * @param key
	 * @return 是否加锁成功
	 */
	boolean lock(String key);

	/**
	 * 对key进行解锁
	 * 
	 * @param key
	 */
	void unlock(String key);

	/**
	 * 根据key设置对应哈希表对象的field - value
	 * 
	 * @param key
	 * @param field
	 * @param value
	 */
	void hset(String key, Serializable field, Serializable value);

	/**
	 * 根据key获取对应哈希表的对应field的对象
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	Object hget(String key, Serializable field);

	/**
	 * 根据key删除对应哈希表的对应field的对象
	 * 
	 * @param key
	 * @param field
	 * @return
	 */
	void hdel(String key, Serializable field);

	/**
	 * 指定的 key 不存在时,为 key 设置指定的value
	 * 
	 * @param key
	 * @param value
	 * @return 是否设置成功
	 */
	boolean setnx(String key, Serializable value);

	/**
	 * 对应key的值自增
	 * 
	 * @param key
	 * @return 自增后的值
	 */
	Long incr(String key);

	/**
	 * 用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始
	 * 
	 * @param key
	 * @param offset
	 *            偏移量
	 * @param value
	 */
	void setrange(String key, long offset, String value);

	/**
	 * 用于获取存储在指定 key 中字符串的子字符串。字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
	 * 
	 * @param key
	 * @param startOffset
	 * @param endOffset
	 * @return
	 */
	String getrange(String key, long startOffset, long endOffset);

	/**
	 * 将value设置至指定key的set集合中
	 * 
	 * @param key
	 * @param value
	 */
	void sadd(String key, Serializable value);

	/**
	 * 获取指定key的set集合
	 * 
	 * @param key
	 * @return
	 */
	Set<?> sall(String key);

	/**
	 * 删除指定key的set集合中的value
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	boolean sdel(String key, Serializable value);
}

复制代码

4.3 定义RedisHelper

基于 SpringRedisTemplate 实现 CacheManager 接口,主要用于对缓存的基本操作,不用于分布式锁作用,此处的分布式锁实现不严谨,不当做参考

/**
 * Redis缓存辅助类
 * 
 * @author ShenHuaJie
 * @version 2016年4月2日 下午4:17:22
 */
public final class RedisHelper implements CacheManager {
	private static final Logger logger = Logger.getLogger(RedisHelper.class);
	private RedisSerializer<String> keySerializer;
	private RedisSerializer<Object> valueSerializer;
	private RedisTemplate<Serializable, Serializable> redisTemplate;
	private final Integer EXPIRE = PropertiesFileUtil.getInstance("redis.properties").getInt("redis.expiration");

	@SuppressWarnings("unchecked")
	public void setRedisTemplate(RedisTemplate<Serializable, Serializable> redisTemplate) {
		this.redisTemplate = redisTemplate;
		this.keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
		this.valueSerializer = (RedisSerializer<Object>) redisTemplate.getValueSerializer();
		CacheUtil.setCacheManager(this);
	}

	@Override
	public final Object get(final String key) {
		// 先过期
		expire(key, EXPIRE);
		// 后取值
		return redisTemplate.boundValueOps(key).get();
	}

	@Override
	public final Set<Object> getAll(final String pattern) {
		Set<Object> values = new HashSet<Object>();
		Set<Serializable> keys = redisTemplate.keys(pattern);
		for (Serializable key : keys) {
			expire(key.toString(), EXPIRE);
			values.add(redisTemplate.opsForValue().get(key));
		}
		return values;
	}

	@Override
	public final void set(final String key, final Serializable value, int seconds) {
		redisTemplate.boundValueOps(key).set(value);
		expire(key, seconds);
	}

	@Override
	public final void set(final String key, final Serializable value) {
		redisTemplate.boundValueOps(key).set(value);
		expire(key, EXPIRE);
	}

	@Override
	public final Boolean exists(final String key) {
		return redisTemplate.hasKey(key);
	}

	@Override
	public final void del(final String key) {
		redisTemplate.delete(key);
	}

	@Override
	public final void delAll(final String pattern) {
		redisTemplate.delete(redisTemplate.keys(pattern));
	}

	@Override
	public final String type(final String key) {
		expire(key, EXPIRE);
		return redisTemplate.type(key).getClass().getName();
	}

	@Override
	public final Boolean expire(final String key, final int seconds) {
		return redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
	}


	@Override
	public final Boolean expireAt(final String key, final long unixTime) {
		return redisTemplate.expireAt(key, new Date(unixTime));
	}

	@Override
	public final Long ttl(final String key) {
		return redisTemplate.getExpire(key, TimeUnit.SECONDS);
	}

	@Override
	public final void setrange(final String key, final long offset, final String value) {
		redisTemplate.boundValueOps(key).set(value, offset);
		expire(key, EXPIRE);
	}

	@Override
	public final String getrange(final String key, final long startOffset, final long endOffset) {
		expire(key, EXPIRE);
		return redisTemplate.boundValueOps(key).get(startOffset, endOffset);
	}

	@Override
	public final Object getSet(final String key, final Serializable value) {
		expire(key, EXPIRE);
		return redisTemplate.boundValueOps(key).getAndSet(value);
	}

	@Override
	public boolean setnx(String key, Serializable value) {
		RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
		RedisConnection redisConnection = null;
		try {
			redisConnection = RedisConnectionUtils.getConnection(factory);
			if (redisConnection == null) {
				return redisTemplate.boundValueOps(key).setIfAbsent(value);
			}
			logger.info(keySerializer);
			logger.info(valueSerializer);
			return redisConnection.setNX(keySerializer.serialize(key), valueSerializer.serialize(value));
		} finally {
			RedisConnectionUtils.releaseConnection(redisConnection, factory);
		}
	}

	@Override
	public boolean lock(String key) {
		RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
		RedisConnection redisConnection = null;
		try {
			redisConnection = RedisConnectionUtils.getConnection(factory);
			if (redisConnection == null) {
				return redisTemplate.boundValueOps(key).setIfAbsent("0");
			}
			return redisConnection.setNX(keySerializer.serialize(key), valueSerializer.serialize("0"));
		} finally {
			RedisConnectionUtils.releaseConnection(redisConnection, factory);
		}
	}

	@Override
	public void unlock(String key) {
		redisTemplate.delete(key);
	}

	@Override
	public void hset(String key, Serializable field, Serializable value) {
		redisTemplate.boundHashOps(key).put(field, value);
	}

	@Override
	public Object hget(String key, Serializable field) {
		return redisTemplate.boundHashOps(key).get(field);
	}

	@Override
	public void hdel(String key, Serializable field) {
		redisTemplate.boundHashOps(key).delete(field);
	}

	@Override
	public void sadd(String key, Serializable value) {
		redisTemplate.boundSetOps(key).add(value);
	}

	@Override
	public Set<?> sall(String key) {
		return redisTemplate.boundSetOps(key).members();
	}

	@Override
	public boolean sdel(String key, Serializable value) {
		return redisTemplate.boundSetOps(key).remove(value) == 1;
	}

	@Override
	public Long incr(String key) {
		return redisTemplate.boundValueOps(key).increment(1L);
	}

}
复制代码

4.4 定义RedissonHelper

基于 Redisson 实现 CacheManager 接口,主要用于实现基于 Redis 的分布式锁

package com.easylink.mall.core.cache.redisson;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.redisson.api.RBucket;
import org.redisson.api.RType;
import org.redisson.api.RedissonClient;

import com.easylink.mall.core.cache.redis.CacheManager;
import com.easylink.mall.core.cache.redis.CacheUtil;
import com.easylink.mall.core.support.util.PropertiesFileUtil;

/**
 * 
 * Redis缓存辅助类
 * 
 */
public class RedissonHelper implements CacheManager {
	private RedissonClient redissonClient;
	private final Integer EXPIRE = PropertiesFileUtil.getInstance("redis.properties").getInt("redis.expiration");

	public void setRedissonClient(Client client) {
		this.redissonClient = client.getRedissonClient();
		CacheUtil.setLockManager(this);
	}

	private RBucket<Object> getRedisBucket(String key) {
		return redissonClient.getBucket(key);
	}

	@Override
	public final Object get(final String key) {
		RBucket<Object> temp = getRedisBucket(key);
		expire(temp, EXPIRE);
		return temp.get();
	}

	@Override
	public final void set(final String key, final Serializable value) {
		RBucket<Object> temp = getRedisBucket(key);
		temp.set(value);
		expire(temp, EXPIRE);
	}

	@Override
	public final void set(final String key, final Serializable value, int seconds) {
		RBucket<Object> temp = getRedisBucket(key);
		temp.set(value);
		expire(temp, seconds);
	}

	public final void multiSet(final Map<String, Object> temps) {
		redissonClient.getBuckets().set(temps);
	}

	@Override
	public final Boolean exists(final String key) {
		RBucket<Object> temp = getRedisBucket(key);
		return temp.isExists();
	}

	@Override
	public final void del(final String key) {
		redissonClient.getKeys().delete(key);
	}

	@Override
	public final void delAll(final String pattern) {
		redissonClient.getKeys().deleteByPattern(pattern);
	}

	@Override
	public final String type(final String key) {
		RType type = redissonClient.getKeys().getType(key);
		if (type == null) {
			return null;
		}
		return type.getClass().getName();
	}

	/**
	 * 在某段时间后失效
	 * 
	 * @return
	 */
	private final void expire(final RBucket<Object> bucket, final int seconds) {
		bucket.expire(seconds, TimeUnit.SECONDS);
	}

	/**
	 * 在某个时间点失效
	 * 
	 * @param key
	 * @param unixTime
	 * @return
	 * 
	 */
	@Override
	public final Boolean expireAt(final String key, final long unixTime) {
		return redissonClient.getBucket(key).expireAt(new Date(unixTime));
	}

	@Override
	public final Long ttl(final String key) {
		RBucket<Object> rBucket = getRedisBucket(key);
		return rBucket.remainTimeToLive();
	}

	@Override
	public final Object getSet(final String key, final Serializable value) {
		RBucket<Object> rBucket = getRedisBucket(key);
		return rBucket.getAndSet(value);
	}

	@Override
	public Set<Object> getAll(String pattern) {
		Set<Object> set = new HashSet<Object>();
		Iterable<String> keys = redissonClient.getKeys().getKeysByPattern(pattern);
		for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
			String key = iterator.next();
			set.add(getRedisBucket(key).get());
		}
		return set;
	}

	@Override
	public Boolean expire(String key, int seconds) {
		RBucket<Object> bucket = getRedisBucket(key);
		expire(bucket, seconds);
		return true;
	}

	@Override
	public void hset(String key, Serializable field, Serializable value) {
		redissonClient.getMap(key).put(field, value);
	}

	@Override
	public Object hget(String key, Serializable field) {
		return redissonClient.getMap(key).get(field);
	}

	@Override
	public void hdel(String key, Serializable field) {
		redissonClient.getMap(key).remove(field);
	}

	public void sadd(String key, Serializable value) {
		redissonClient.getSet(key).add(value);
	}

	public Set<Object> sall(String key) {
		return redissonClient.getSet(key).readAll();
	}

	public boolean sdel(String key, Serializable value) {
		return redissonClient.getSet(key).remove(value);
	}

	@Override
	public boolean lock(String key) {
		return redissonClient.getLock(key).tryLock();
	}

	@Override
	public void unlock(String key) {
		redissonClient.getLock(key).unlock();
	}

	@Override
	public boolean setnx(String key, Serializable value) {
		try {
			return redissonClient.getLock(key).tryLock(Long.valueOf(value.toString()), TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			return false;
		}
	}

	@Override
	public Long incr(String key) {
		return null;
	}

	@Override
	public void setrange(String key, long offset, String value) {
	}

	@Override
	public String getrange(String key, long startOffset, long endOffset) {
		return null;
	}
}
复制代码

4.5 定义Redisson客户端配置实现类

package com.easylink.mall.core.cache.redisson;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.SingleServerConfig;

/**
 * Redis连接配置
 * 
 * @author ShenHuaJie
 * @since 2017年8月23日 上午9:36:53
 */
public class Client {
	/**
	 * Redis server address
	 *
	 */
	private String address;

	/**
	 * Password for Redis authentication. Should be null if not needed
	 */
	private String password;

	/**
	 * Redis cluster node urls list
	 */
	private Set<String> nodeAddresses = new HashSet<String>();

	/**
	 * Redis master server address
	 */
	private String masterAddress;

	/**
	 * Redis slave servers addresses
	 */
	private Set<String> slaveAddresses = new HashSet<String>();

	private RedissonClient redissonClient;

	public void init() {
		Config config = new Config();
		if (StringUtils.isNotBlank(address)) {
			SingleServerConfig serverConfig = config.useSingleServer().setAddress(address);
			if (StringUtils.isNotBlank(password)) {
				serverConfig.setPassword(password);
			}
		} else if (!nodeAddresses.isEmpty()) {
			ClusterServersConfig serverConfig = config.useClusterServers()
					.addNodeAddress(nodeAddresses.toArray(new String[] {}));
			if (StringUtils.isNotBlank(password)) {
				serverConfig.setPassword(password);
			}
		} else if (masterAddress != null && !slaveAddresses.isEmpty()) {
			MasterSlaveServersConfig serverConfig = config.useMasterSlaveServers().setMasterAddress(masterAddress)
					.addSlaveAddress(slaveAddresses.toArray(new String[] {}));
			if (StringUtils.isNotBlank(password)) {
				serverConfig.setPassword(password);
			}
		}
		this.redissonClient = Redisson.create(config);
	}

	public RedissonClient getRedissonClient() {
		return redissonClient;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setNodeAddresses(String nodeAddresse) {
		if (nodeAddresse != null) {
			String[] nodeAddresses = nodeAddresse.split(",");
			for (int i = 0; i < nodeAddresses.length; i++) {
				if (StringUtils.isNotEmpty(nodeAddresses[i])) {
					this.nodeAddresses.add(nodeAddresses[i]);
				}
			}
		}
	}

	public void setMasterAddress(String masterAddress) {
		this.masterAddress = masterAddress;
	}

	public void setSlaveAddresses(String slaveAddresse) {
		if (slaveAddresse != null) {
			String[] slaveAddresses = slaveAddresse.split(",");
			for (int i = 0; i < slaveAddresses.length; i++) {
				if (StringUtils.isNotEmpty(slaveAddresses[i])) {
					this.slaveAddresses.add(slaveAddresses[i]);
				}
			}
		}
	}
}

复制代码

4.6 定义properties配置文件读取工具类

package com.easylink.mall.core.support.util;

import java.util.HashMap;

import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.log4j.Logger;

/**
 * 资源文件读取工具
 * 
 * @author Ben.
 *
 */
public class PropertiesFileUtil {

	private static Logger logger = Logger.getLogger(PropertiesFileUtil.class);
	// 当打开多个资源文件时,缓存资源文件
	private static HashMap<String, PropertiesConfiguration> configMap = new HashMap<String, PropertiesConfiguration>();
	// 默认资源文件名称
	private static final String NAME = "config.properties";

	// 私有构造方法,创建单例
	private PropertiesFileUtil() {
	}

	public static synchronized PropertiesConfiguration getInstance() {
		return getInstance(NAME);
	}

	public static synchronized PropertiesConfiguration getInstance(String name) {
		PropertiesConfiguration propertiesConfiguration = configMap.get(name);
		if (propertiesConfiguration == null) {
			Configurations configs = new Configurations();
			try {
				propertiesConfiguration = configs.properties(name);
			} catch (ConfigurationException e) {
				logger.error("can not load properties file,name : " + name);
			}
			configMap.put(name, propertiesConfiguration);
		}
		return propertiesConfiguration;
	}
}

复制代码

5. 测试

编写单元测试用例,测试是否搭建成功

5.1 测试基本操作

package com.easylink.mall.core.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.easylink.mall.core.cache.redis.CacheUtil;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/spring-redis.xml")
public class JedisTest {

	 @Test
	public void execute() {
		CacheUtil.getCache().set("test-jedis", "test-value");
		Object testValue = CacheUtil.getCache().get("test-jedis");
		System.out.println(String.valueOf(testValue));
	}

}

复制代码

5.2 测试分布式锁

package com.easylink.mall.core.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.easylink.mall.core.cache.redis.CacheUtil;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/spring-redisson.xml")
public class RedissonTest {

	@Test
	public void execute() {
		// 加锁
		CacheUtil.getLockManager().lock("test-jedis");
		// 解锁
		CacheUtil.getLockManager().unlock("test-jedis");
	}

}

复制代码
原文  https://juejin.im/post/5b8e251df265da4326074ae2
正文到此结束
Loading...