您的位置:首页 > 数据库 > Redis

spring-data-redis 整合,以及使用kryo序列化代替jdk原生序列化机制

2017-04-02 12:10 991 查看
之前一直没使用spring-data-redis模板进行redis操作,周日闲着没事,整合了下,又想不适用jdk原生的序列化,于是自己简单的,参考网上的,后期路过的坑,修改了下,

实验发现,kryo还是不适合作为 持久化的序列化使用的, kryo序列化仅做参考吧

引入 spring-data-redis maven依赖

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.0.RELEASE</version>
</dependency>
redisclients一定要2.9以上啊,注意项目中引入的jedis版本已经是否被其他依赖替换了
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>


上配置,自己简单看看源码,就知道配置什么意思了,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> 
<!-- 连接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30" />
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10" />
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<!-- jedis客户端单机版 -->
<!-- <bean id="deepFashionRedisClient" class="redis.clients.jedis.JedisPool"> <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg> <constructor-arg name="host" value="${redis.host}"></constructor-arg>
<constructor-arg name="port" value="${redis.port}"></constructor-arg> <constructor-arg name="timeout" value="${redis.timeout}"></constructor-arg> <constructor-arg name="password" value="${redis.password}"></constructor-arg>
</bean> -->
<bean id="jedisClient" class="cn.deepfashion.manager.cache.impl.JedisClientTem">
<property name="prefix" value="${redis.key.prefix}"></property>
</bean>

<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="poolConfig" ref="jedisPoolConfig"></property>
<property name="hostName" value="${redis.host}"></property>
<property name="port" value="${redis.port}"></property>
<property name="timeout" value="${redis.timeout}"></property>
<property name="password" value="${redis.password}"></property>
</bean>

<bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="keySerializer">
<!-- 键值对的key的序列化机制为string -->
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="defaultSerializer">
<!-- 默认的序列化机制为kryo 自己看看源码 很简单,里面很多-->
<bean class="cn.deepfashion.redis.serializer.KryoRedisSerializer"></bean>
</property>
</bean>

<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" parent="jedisTemplate" />

</beans>


下面开始贴出来简单封装的模板先贴实现类,遇到的坑已经写上注释了

package cn.deepfashion.manager.cache.impl;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.util.CollectionUtils;

import cn.deepfashion.manager.cache.JedisClient;
import cn.deepfashion.manager.logger.DeepFashionLoggerFactory;

/**
* jedis客户端
*
* @author zmh
*
* @param <V>
*            2017年4月2日
*/
public class JedisClientTem<V> implements JedisClient<V> {

private static String prefix;
private static final Logger logger = DeepFashionLoggerFactory.getLogger(JedisClientTem.class);

@Resource
RedisTemplate<String, V> jedisTemplate;
@Resource
StringRedisTemplate stringRedisTemplate;

/**
* 缓存基本的对象
*
* @param key
*            缓存的键值
* @param value
*            缓存的值
* @return 缓存的对象
*/
@Override
public void set(String key, V value) {
try {
jedisTemplate.opsForValue().set(getKey(key), value);
} catch (Exception e) {
logger.warn("RedisTemplate::set,key={},value={}", key, value, e);
}
}

/**
* 缓存对象
*
* @param key
* @param seconds
*            秒
* @param value
*            2017年3月26日
*/
@Override
public void set(String key, int seconds, V value) {
try {

jedisTemplate.opsForValue().set(getKey(key), value, seconds, TimeUnit.SECONDS);
} catch (Exception e) {
logger.warn("RedisTemplate::set,key={},value={},seconds={}", key, value, seconds, e);
}
}

/**
* 获得缓存的基本对象。
*
* @param key
*            缓存键值
* @return 缓存键值对应的数据
*/
@Override
public V get(String key) {
V value = null;
try {
value = jedisTemplate.opsForValue().get(getKey(key));
} catch (Exception e) {
logger.warn("RedisTemplate::get, key={}", key, e);
}
return value;
}

/**
* 缓存 基本 Integer、String、实体类等
*
* @param key
* @param value
*            2017年4月2日
*/
@Override
public void setString(String key, int seconds, String value) {
try {
stringRedisTemplate.opsForValue().set(getKey(key), value, seconds, TimeUnit.SECONDS);
} catch (Exception e) {
logger.warn("RedisTemplate::setString,key={},value={},seconds={}", key, value, seconds, e);
}
}

/**
* 获取基本类型值
*
* @param key
* @return 2017年4月2日
*/
@Override
public String getString(String key) {
String value = null;
try {
value = stringRedisTemplate.opsForValue().get(getKey(key));
} catch (Exception e) {
logger.warn("RedisTemplate::getString, key={}", key, e);
}
return value;
}

/**
* 设置值的有效时间
*
* @param key
* @param second
* @return 2017年3月26日
*/
@Override
public Boolean expire(String key, long second) {
boolean result = false;

try {
result = jedisTemplate.expire(getKey(key), second, TimeUnit.SECONDS);
} catch (Exception e) {
logger.warn("RedisTemplate::expire, key={}, second={}", key, second, e);
}

return result;
}

/**
* 获取值的有效时间
*
* @param key
* @return 2017年3月26日
*/
@Override
public long getExpire(String key) {
long result = 0;
try {
result = jedisTemplate.getExpire(getKey(key), TimeUnit.SECONDS);
} catch (Exception e) {
logger.warn("RedisTemplate::getExpire, key={}", key, e);
}

return result;
}

/**
* 删除值
*
* @param key
*            2017年3月26日
*/
@Override
public void delete(String key) {
try {

jedisTemplate.delete(getKey(key));
} catch (Exception e) {
logger.warn("RedisTemplate::delete, key={}", key, e);
}
}

/**
* 对象是否存在
*
* @param key
* @return 2017年3月26日
*/
@Override
public Boolean hasKey(String key) {
boolean result = false;
try {

result = jedisTemplate.hasKey(getKey(key));
} catch (Exception e) {
logger.warn("RedisTemplate::hasKey, key={}", key, e);
}

return result;
}

/**
* 缓存List数据
*
* @param key
*            缓存的键值
* @param dataList
*            待缓存的List数据
* @return 缓存的对象
*/
@Override
public void listAddAll(String key, List<V> dataList) {
if (CollectionUtils.isEmpty(dataList)) {
return;
}

try {
ListOperations<String, V> listOperation = jedisTemplate.opsForList();
String pfKey = getKey(key);
for (V v : dataList) {
listOperation.rightPush(pfKey, v);
}
} catch (Exception e) {
logger.warn("RedisTemplate::listAddAll, key={}, dataList={}", key, dataList, e);
}
}

/**
* 缓存List数据(从右侧依次添加 不会覆盖原来的数据)
*
* @param key
*            缓存的键值
* @param dataList
*            待缓存的List数据
* @return 缓存的对象
*/
@Override
public void listAddAll(String key, int seconds, List<V> dataList) {
if (CollectionUtils.isEmpty(dataList)) {
return;
}
try {
ListOperations<String, V> listOperation = jedisTemplate.opsForList();

String pfKey = getKey(key);

// rightPushAll 方法---自己感觉是个大坑,在队列中,竟然把dataList 看成是一个元素,也是醉了,我还以为是一次添加所有元素到队列中
// listOperation.rightPushAll(pfKey, dataList);

for (V v : dataList) {
listOperation.rightPush(pfKey, v);
}

this.expire(getKey(key), seconds);
} catch (Exception e) {
logger.warn("RedisTemplate::listAddAll, key={}, dataList={},seconds={}", key, dataList, seconds, e);
}
}

/**
* 获得缓存的list对象
*
* @param key
*            缓存的键值
* @return 缓存键值对应的数据
*/
@Override
public List<V> listGetAll(String key) {
List<V> result = null;
try {
ListOperations<String, V> listOperation = jedisTemplate.opsForList();
result = listOperation.range(getKey(key), 0, -1);
} catch (Exception e) {
result = Collections.emptyList();
logger.warn("RedisTemplate::getList, key={}", key, e);
}
return result;
}

/**
* 用指定元素替换此列表中指定位置的元素(可选操作)
*/
@Override
public void listSet(String key, long index, V value) {
try {
ListOperations<String, V> listOperation = jedisTemplate.opsForList();
listOperation.set(getKey(key), index, value);
} catch (Exception e) {
logger.warn("RedisTemplate::listSet, key={}, dataList={}, value={}", key, value, e);
}
}

/**
* 缓存Map
*
* @param key
* @param dataMap
* @return
*/
@Override
public void mapPutAll(String key, Map<String, V> dataMap) {
try {

HashOperations<String, Object, V> hashOperations = jedisTemplate.opsForHash();
hashOperations.putAll(getKey(key), dataMap);
} catch (Exception e) {
logger.warn("RedisTemplate::mapPutAll, key={},dataMap={}", key, dataMap, e);
}
}

@Override
public void mapPutAll(String key, int seconds, Map<String, V> dataMap) {
try {

HashOperations<String, Object, V> hashOperations = jedisTemplate.opsForHash();
hashOperations.putAll(getKey(key), dataMap);
this.expire(getKey(key), seconds);
} catch (Exception e) {
logger.warn("RedisTemplate::mapPutAll, key={},dataMap={}", key, dataMap, e);
}
}

/**
* 获得缓存的Map
*
* @param key
* @param hashOperation
* @return
*/
@Override
public Map<Object, Object> mapGetAll(String key) {
Map<Object, Object> result = null;
try {
result = jedisTemplate.opsForHash().entries(getKey(key));
} catch (Exception e) {
result = Collections.emptyMap();
logger.warn("RedisTemplate::getMap, key={}", key, e);
}
return result;
}

/**
* 获取map中指定的值
*
* @param key
* @param hashKey
* @return 2017年3月26日
*/
@Override
public Object mapGet(String key, Object hashKey) {
Object result = null;
try {
result = jedisTemplate.opsForHash().hasKey(getKey(key), hashKey);
} catch (Exception e) {
logger.warn("RedisTemplate::getMapValue, key={},mapKey={}", key, hashKey, e);
}
return result;
}

@Override
public void mapPut(String key, String hashKey, V value) {
try {
HashOperations<String, Object, V> hashOperations = jedisTemplate.opsForHash();
hashOperations.put(getKey(key), hashKey, value);
} catch (Exception e) {
logger.warn("RedisTemplate::mapPutAll, key={},value={}", key, value, e);
}

}

/**
* 缓存Set
*
* @param key
*            缓存键值
* @param dataSet
*            缓存的数据
* @return 缓存数据的对象
*/
@SuppressWarnings("unchecked")
@Override
public void setAddAll(String key, Set<V> dataSet) {
try {

BoundSetOperations<String, V> setOperation = jedisTemplate.boundSetOps(getKey(key));
Iterator<V> it = dataSet.iterator();
while (it.hasNext()) {
setOperation.add(it.next());
}
} catch (Exception e) {
logger.warn("RedisTemplate::setAddAll, key={},dataSet={}", key, dataSet, e);
}
}

/**
* 获得缓存的set
*
* @param key
* @param operation
* @return
*/
@Override
public Set<V> getSet(String key) {
Set<V> result = null;
try {
BoundSetOperations<String, V> operation = jedisTemplate.boundSetOps(getKey(key));
result = operation.members();
} catch (Exception e) {
result = Collections.emptySet();
logger.warn("RedisTemplate::getSet, key={}", key, e);
}
return result;
}

/**
* 获取list模板操作list集合
*
* @return 2017年3月26日
*/
@Override
public ListOperations<String, V> listTemplate() {
return jedisTemplate.opsForList();
}

/**
* 获取map模板操作map
*
* @return 2017年3月26日
*/
@Override
public HashOperations<String, String, Object> mapTemplate() {
return jedisTemplate.opsForHash();
}

/**
* 获取有序集合模板
*
* @return 2017年3月26日
*/
@Override
public ZSetOperations<String, V> zSetTemplate() {
return jedisTemplate.opsForZSet();
}

@Override
public ValueOperations<String, V> valueTemplate() {
return jedisTemplate.opsForValue();
}

public static String getKey(String key) {
return prefix + key;
}

public static String getPrefix() {
return prefix;
}

public static void setPrefix(String prefix) {
JedisClientTem.prefix = prefix;
}

public RedisTemplate<String, V> getJedisTemplate() {
return jedisTemplate;
}

public void setJedisTemplate(RedisTemplate<String, V> jedisTemplate) {
this.jedisTemplate = jedisTemplate;
}

@Override
public StringRedisTemplate getStringTemplate() {
return stringRedisTemplate;
}

public ValueOperations<String, String> stringValueTemplate() {
return stringRedisTemplate.opsForValue();
}

}


下面是接口

package cn.deepfashion.manager.cache;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;

public interface JedisClient<V> {

/**
* 缓存对象
*
* @param key
*            缓存的键值
* @param value
*            缓存的值
* @return 缓存的对象
*/
public void set(String key, V value);

/**
* 缓存对象
*
* @param key
* @param seconds
*            秒
* @param value
*            2017年3月26日
*/
public void set(String key, int seconds, V value);

/**
* 缓存 基本 Integer、String、实体类等
*
* @param key
* @param value
*            2017年4月2日
*/
public void setString(String key, int seconds, String value);

/**
* 获取基本类型值
*
* @param key
* @return 2017年4月2日
*/
public String getString(String key);

/**
* 获得缓存的基本对象。
*
* @param key
*            缓存键值
* @return 缓存键值对应的数据
*/
public V get(String key);

/**
* 设置值的有效时间
*
* @param key
* @param second
* @return 2017年3月26日
*/
public Boolean expire(String key, long second);

/**
* 获取值的有效时间
*
* @param key
* @return 2017年3月26日
*/
public long getExpire(String key);

/**
* 删除值
*
* @param key
*            2017年3月26日
*/
public void delete(String key);

/**
* 对象是否存在
*
* @param key
* @return 2017年3月26日
*/
public Boolean hasKey(String key);

/**
* 缓存List数据(从右侧依次添加 不会覆盖原来的数据)
*
* @param key
*            缓存的键值
* @param dataList
*            待缓存的List数据
* @return 缓存的对象
*/
public void listAddAll(String key, List<V> dataList);

/**
* 缓存List数据(从右侧依次添加 不会覆盖原来的数据)
*
* @param key
*            缓存的键值
* @param dataList
*            待缓存的List数据
* @return 缓存的对象
*/
public void listAddAll(String key, int seconds, List<V> dataList);

/**
* 获得缓存的list对象
*
* @param key
*            缓存的键值
* @return 缓存键值对应的数据
*/
public List<V> listGetAll(String key);

/**
* 用指定元素替换此列表中指定位置的元素(可选操作)
*
* @param key
* @param value
*            2017年3月31日
*/
public void listSet(String key, long index, V value);

/**
* 缓存Map
*
* @param key
* @param dataMap
* @return
*/
public void mapPutAll(String key, Map<String, V> dataMap);

/**
* 添加map
*
* @param key
* @param seconds
* @param dataMap
*            2017年3月31日
*/
public void mapPutAll(String key, int seconds, Map<String, V> dataMap);

/**
* 获得缓存的Map
*
* @param key
* @param hashOperation
* @return
*/
public Map<Object, Object> mapGetAll(String key);

/**
* map 添加数据
*
* @param key
* @param hashKey
* @param value
*            2017年3月31日
*/
public void mapPut(String key, String hashKey, V value);

/**
* 获取map中指定的值
*
* @param key
* @param hashKey
* @return 2017年3月26日
*/
public Object mapGet(String key, Object hashKey);

/**
* 缓存Set
*
* @param key
*            缓存键值
* @param dataSet
*            缓存的数据
* @return 缓存数据的对象
*/
public void setAddAll(String key, Set<V> dataSet);

/**
* 获得缓存的set
*
* @param key
* @param operation
* @return
*/
public Set<V> getSet(String key);

/**
* 获取list模板操作list集合
*
* @return 2017年3月26日
*/
public ListOperations<String, V> listTemplate();

/**
* 获取map模板操作map
*
* @return 2017年3月26日
*/
public HashOperations<String, String, Object> mapTemplate();

/**
* 获取有序集合模板
*
* @return 2017年3月26日
*/
public ZSetOperations<String, V> zSetTemplate();

/**
* 获取基本value模板
*
* @return 2017年3月27日
*/
public ValueOperations<String, V> valueTemplate();

public RedisTemplate<String, V> getJedisTemplate();

public StringRedisTemplate getStringTemplate();

public ValueOperations<String, String> stringValueTemplate();
}

然后最后是kryo的序列化实现

package cn.deepfashion.redis.serializer;

import java.io.InputStream;
import java.io.OutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import cn.deepfashion.common.util.SerializerUtils;

/**
* 以后处理并发问题
* @author zmh
*
* @param <T>
*            2017年4月2日
*/
@SuppressWarnings("unchecked")
public class KryoRedisSerializer<T> implements RedisSerializer<T> {

private final static Logger logger = LoggerFactory.getLogger(KryoRedisSerializer.class);

@Override
public byte[] serialize(Object obj) throws SerializationException {
if (obj == null) {
return SerializerUtils.EMPTY_ARRAY;
}
Kryo kryo = kryos.get();
Output output = new Output(64, -1);

try {
kryo.writeClassAndObject(output, obj);
return output.toBytes();
} finally {
closeOutputStream(output);
}

}

@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (SerializerUtils.isEmpty(bytes)) {
return null;
}
Kryo kryo = kryos.get();
Input input = null;
try {
input = new Input(bytes);
return (T) kryo.readClassAndObject(input);
} finally {
closeInputStream(input);
}
}

private static void closeOutputStream(OutputStream output) {
if (output != null) {
try {
output.flush();
output.close();
} catch (Exception e) {
logger.error("serialize object close outputStream exception", e);
}
}
}

private static void closeInputStream(InputStream input) {
if (input != null) {
try {
input.close();
} catch (Exception e) {
logger.error("serialize object close inputStream exception", e);
}
}
}

private static final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() {
protected Kryo initialValue() {
Kryo kryo = new Kryo();
return kryo;
};
};

}


ok完毕

/**
* 空byte数组
*/
public static final byte[] EMPTY_ARRAY = new byte[0];
public static boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息