#前言
Java
缓存实现方案有很多,最基本的自己使用 Map
去构建缓存,再高级点的使用 Ehcache
或者 Goolge
的 guava
作为内存缓存框架, Ehcache
可以满足单机缓存的需求( Ehcache
的具体使用在我过往的文章中有所介绍),如果我们是多台机子共用缓存数据的话, Ehcache
可通过 rmi
, jgroup
, jms
的方式实现,但是实用性与操作性不高且复杂,现时大部分应用仅用 Ehcache
作为单机缓存使用,这时候我们可以通过搭建缓存服务器解决多机使用的问题,常见的缓存服务器有 Memcached
, Redis
等。
现时业界主流大多使用 Redis
。所以本文主要介绍在 Java
中如何使用 Redis
。至于如何搭建 Redis
,我在过往的文章中已有所介绍,不知道如何搭建的同学,可以参考我过往的文章,下文所用到相关的 Redis
信息均为搭建教程中的信息。
PS:文章中所用到的示例代码,部分参考至开源项目iBase4J,特此声明。
本文同步发布于简书 : www.jianshu.com/p/5a9946870…
Java
连接 Redis
官方推荐的是使用 Jedis
和 Redisson
进行连接操作, Spring
对 Redis
有很好的支持,所以此文我结合 Spring
中的 Spring Data
对 Redis
进行操作。
<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> 复制代码
在 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 复制代码
在 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> 复制代码
在 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> 复制代码
这个类主要是用于获取缓存管理器,因为 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); } } 复制代码
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); } 复制代码
基于 Spring
的 RedisTemplate
实现 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); } } 复制代码
基于 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; } } 复制代码
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]); } } } } } 复制代码
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; } } 复制代码
编写单元测试用例,测试是否搭建成功
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)); } } 复制代码
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"); } } 复制代码