隻使用了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官方文檔