前言
Java缓存实现方案有很多,最基本的自己使用Map去构建缓存,再高级点的使用Ehcache或者Goolge的guava作为内存缓存框架,Ehcache可以满足单机缓存的需求(Ehcache的具体使用在我过往的文章中有所介绍),如果我们是多台机子共用缓存数据的话,Ehcache可通过rmi,jgroup,jms的方式实现,但是实用性与操作性不高且复杂,现时大部分应用仅用Ehcache作为单机缓存使用,这时候我们可以通过搭建缓存服务器解决多机使用的问题,常见的缓存服务器有Memcached,Redis等。
现时业界主流大多使用Redis。所以本文主要介绍在Java中如何使用Redis。至于如何搭建Redis,我在过往的文章中已有所介绍,不知道如何搭建的同学,可以参考我过往的文章,下文所用到相关的Redis信息均为搭建教程中的信息。
PS:文章中所用到的示例代码,部分参考至开源项目iBase4J,特此声明。
Java连接Redis
Java连接Redis官方推荐的是使用Jedis和Redisson进行连接操作,Spring对Redis有很好的支持,所以此文我结合Spring中的Spring Data对Redis进行操作。
1. maven引用
org.springframework.data
spring-data-redis
1.8.7.RELEASE
redis.clients
jedis
2.9.0
org.redisson
redisson
3.5.5
2. 建立Redis配置文件
在classpath下建立Redis配置文件redis.properties。
如果同学们是搭建Redis高可用架构,是通过向外提供VIP虚拟IP的方式连接Redis,则只需在配置文件中将redis.host=172.16.2.185单机IP改为VIP虚拟IPredis.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。
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"
>
3.2 配置Redisson实现
在spring文件夹下建立spring-redisson.xml,主要用于注入Redisson
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"
>
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 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删除对象
*
* @para