只使用了Redis的单节点连接配置, JedisCluster 和 Sentinel 已被注释,未测试。
SSM项目搭建
参考 SSM项目简单整合
建立配置文件
- pom.xml 中需添加以下依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.4.RELEASE</version>
</dependency>
- spring-redis.xml
<?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">
<!-- spring扫描此包下附带注解的类,将其作为bean管理-->
<context:component-scan base-package="com.yingjun.ssm.cache" />
<!-- 引入redis配置 -->
<context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>
<!-- Jedis 配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}" />
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>
<!-- redisTemplate配置,redisTemplate是对Jedis的对redis操作的扩展,有更多的操作,封装使操作更便捷 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>
<!-- redis单节点数据库连接配置 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.ip}" />
<property name="port" value="${redis.port}" />
<property name="password" value="${redis.pass}" />
<property name="poolConfig" ref="jedisPoolConfig" />
</bean>
<!-- JedisCluster 集群高可用配置 -->
<!--<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg index="0">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.ip1}" />
<constructor-arg index="1" value="${redis.port1}" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.ip2}" />
<constructor-arg index="1" value="${redis.port2}" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.ip3}" />
<constructor-arg index="1" value="${redis.port3}" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.ip4}" />
<constructor-arg index="1" value="${redis.port4}" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.ip5}" />
<constructor-arg index="1" value="${redis.port5}" type="int" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="${redis.ip6}" />
<constructor-arg index="1" value="${redis.port6}" type="int" />
</bean>
</set>
</constructor-arg>
<constructor-arg index="1" value="2000" type="int"></constructor-arg>
<constructor-arg index="2" value="100" type="int"></constructor-arg>
<constructor-arg index="3" ref="jedisPoolConfig"></constructor-arg>
</bean>-->
<!--redis Sentinel主从高可用方案配置 -->
<!-- <bean id="sentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<property name="master">
<bean class="org.springframework.data.redis.connection.RedisNode">
<property name="name" value="master-1"></property>
</bean>
</property>
<property name="sentinels">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${sentinel1.ip}"></constructor-arg>
<constructor-arg name="port" value="${sentinel1.port}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${sentinel2.ip}"></constructor-arg>
<constructor-arg name="port" value="${sentinel2.port}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${sentinel3.ip}"></constructor-arg>
<constructor-arg name="port" value="${sentinel3.port}"></constructor-arg>
</bean>
</set>
</property>
</bean>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true">
<property name="password" value="${redis.pass}" />
<property name="poolConfig">
<ref bean="jedisPoolConfig" />
</property>
<constructor-arg name="sentinelConfig" ref="sentinelConfiguration" />
</bean> -->
</beans>
- redis.properties
# Redis Config
#redis server ip and port
redis.ip=127.0.0.1
redis.port=6379
# Redis server password
redis.pass=0000
# 最大连接数
redis.pool.maxTotal=105
# 最大空闲数
redis.pool.maxIdle=10
# 最大建立连接等待时间
redis.pool.maxWaitMillis=5000
# 指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
redis.pool.testOnBorrow=true
# redis sentinel config
#sentinel1.ip=192.168.11.100
#sentinel1.port=63791
#sentinel2.ip=192.168.11.101
#sentinel2.port=63792
#sentinel3.ip=192.168.11.102
#sentinel3.port=63792
# reids cluster config
#redis.ip1=192.168.11.100
#redis.port1=7111
#redis.ip2=192.168.11.101
#redis.port2=7112
#redis.ip3=192.168.11.102
#redis.port3=7113
#redis.ip4=192.168.11.103
#redis.port4=7114
#redis.ip5=192.168.11.104
#redis.port5=7115
#redis.ip6=192.168.11.105
#redis.port6=7116
Redis工具类
此工具类的内部实现原理请在开发工具中查看函数源码
package com.yingjun.ssm.cache;
import com.yingjun.ssm.util.ProtoStuffSerializerUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Set;
/**
* redis缓存
* @author yingjun
*
*/
@Component
public class RedisCache {
public final static int CAHCETIME=60;//默认缓存时间
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 存入缓存
* @param key
* @param obj
* @param <T>
* @return
*/
public <T> boolean putCache(String key, T obj) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);//将对象序列化为byte
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(bkey, bvalue);
}
});
return result;
}
/**
* 存入缓存并设置有效时间
* @param key
* @param obj
* @param expireTime
* @param <T>
*/
public <T> void putCacheWithExpireTime(String key, T obj, final long expireTime) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.setEx(bkey, expireTime, bvalue);
return true;
}
});
}
/**
* 存入list到缓存
* @param key
* @param objList
* @param <T>
* @return
*/
public <T> boolean putListCache(String key, List<T> objList) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(bkey, bvalue);
}
});
return result;
}
/**
* 存入list到缓存,并设置有效时间
* @param key
* @param objList
* @param expireTime
* @param <T>
* @return
*/
public <T> boolean putListCacheWithExpireTime(String key, List<T> objList, final long expireTime) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.setEx(bkey, expireTime, bvalue);
return true;
}
});
return result;
}
/**
* 根据key读取缓存
* @param key
* @param targetClass
* @param <T>
* @return
*/
public <T> T getCache(final String key, Class<T> targetClass) {
byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
@Override
public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
return connection.get(key.getBytes());
}
});
if (result == null) {
return null;
}
return ProtoStuffSerializerUtil.deserialize(result, targetClass);
}
/**
* 根据key从缓存中读取数组
* @param key
* @param targetClass
* @param <T>
* @return
*/
public <T> List<T> getListCache(final String key, Class<T> targetClass) {
byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
@Override
public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
return connection.get(key.getBytes());
}
});
if (result == null) {
return null;
}
return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
}
/**
* 精确删除key
*
* @param key
*/
public void deleteCache(String key) {
redisTemplate.delete(key);
}
/**
* 模糊删除key
*
* @param pattern 使用通配符匹配 比如 goods|* 可以查询到 goods|xx, goods|zz之类的key集合
*/
public void deleteCacheWithPattern(String pattern) {
//根据pattern获取模糊匹配的key集合
Set<String> keys = redisTemplate.keys(pattern);
//批量删除
redisTemplate.delete(keys);
}
}
实际使用
- 类字段需要注入Redis工具
@Autowired
private RedisCache cache;
- 使用举例
public void putUserInCache(int userIndex, String userName){
// key的格式自己决定 比如该key的格式为: "test|user|xxxx" 表示test项目的某位用户
String key = "test" + "|user|" + userIndex;
// 将key-value存入Redis
cache.putCache(key,userName);
// 根据key取出value,此处value为String类型,所以第二参数需要传入 String.class
String getName = cache.getCache(key,String.class);
// 清除所有缓存(慎用),使用通配符匹配,则所有test项目的缓存都被删除
cache.deleteCacheWithPattern("test|*");
}
附
采用Jedis Cluster的Redis工具类(未测试)
- RedisClusterCache.java
package com.yingjun.ssm.cache;
import com.yingjun.ssm.util.ProtoStuffSerializerUtil;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* redis缓存
*
* 采用Jedis Cluster
*
* @author yingjun
*
*/
@Component
public class RedisClusterCache {
public final static String CAHCENAME="cache";//缓存名
public final static int CAHCETIME=60;//默认缓存时间
//@Autowired
private JedisCluster jedisCluster;
public <T> void putCache(String key, T obj) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
jedisCluster.set(bkey,bvalue);
}
public <T> void putCacheWithExpireTime(String key, T obj, int expireTime) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
jedisCluster.setex(bkey, expireTime, bvalue);
}
public <T> void putListCache(String key, List<T> objList) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
jedisCluster.set(bkey,bvalue);
}
public <T> void putListCacheWithExpireTime(String key, List<T> objList, int expireTime) {
final byte[] bkey = key.getBytes();
final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
jedisCluster.setex(bkey, expireTime, bvalue);
}
public <T> T getCache(final String key, Class<T> targetClass) {
byte[] result =jedisCluster.get(key.getBytes());
if (result == null) {
return null;
}
return ProtoStuffSerializerUtil.deserialize(result, targetClass);
}
public <T> List<T> getListCache(String key, Class<T> targetClass) {
byte[] result =jedisCluster.get(key.getBytes());
if (result == null) {
return null;
}
return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
}
/**
* 精确删除key
*
* @param key
*/
public void deleteCache(String key) {
jedisCluster.del(key);
}
/**
* 模糊删除key
*
* @param pattern
*/
public void deleteCacheWithPattern(String pattern) {
Set<String> keys =this.keys(pattern);
for(String key:keys){
jedisCluster.del(key);
}
}
/**
* 清空所有缓存
*/
public void clearCache() {
deleteCacheWithPattern(RedisClusterCache.CAHCENAME+"|*");
}
/**
* 由于JedisCluster没有提供对keys命令的封装,只能自己实现
* @param pattern
* @return
*/
public Set<String> keys(String pattern){
Set<String> keys = new HashSet<>();
Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
for(String k : clusterNodes.keySet()){
JedisPool jp = clusterNodes.get(k);
Jedis connection = jp.getResource();
try {
keys.addAll(connection.keys(pattern));
} catch(Exception e){
e.printStackTrace();
} finally{
//用完一定要close这个链接!!!
connection.close();
}
}
return keys;
}
}
参考
源码来自:优雅的SSM(Spring+SpringMVC+Mybatis)框架
其他参考:
windows后台运行redis
Spring整合redis,通过sentinel进行主从切换。(何志雄)
redis整合spring(redisTemplate工具类)
Spring-Data-Redis存储对象(redisTemplate)
Redis官方文档