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

来源:互联网 发布:pdf转换mobi软件 编辑:程序博客网 时间:2024/05/07 07:22

之前一直没使用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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://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.xsdhttp://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);@ResourceRedisTemplate<String, V> jedisTemplate;@ResourceStringRedisTemplate stringRedisTemplate;/** * 缓存基本的对象 *  * @param key *            缓存的键值 * @param value *            缓存的值 * @return 缓存的对象 */@Overridepublic 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日 */@Overridepublic 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 缓存键值对应的数据 */@Overridepublic 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日 */@Overridepublic 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日 */@Overridepublic 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日 */@Overridepublic 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日 */@Overridepublic 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日 */@Overridepublic 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日 */@Overridepublic 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 缓存的对象 */@Overridepublic 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 缓存的对象 */@Overridepublic 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 缓存键值对应的数据 */@Overridepublic 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;}/** * 用指定元素替换此列表中指定位置的元素(可选操作) */@Overridepublic 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 */@Overridepublic 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);}}@Overridepublic 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 */@Overridepublic 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日 */@Overridepublic 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;}@Overridepublic 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")@Overridepublic 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 */@Overridepublic 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日 */@Overridepublic ListOperations<String, V> listTemplate() {return jedisTemplate.opsForList();}/** * 获取map模板操作map *  * @return 2017年3月26日 */@Overridepublic HashOperations<String, String, Object> mapTemplate() {return jedisTemplate.opsForHash();}/** * 获取有序集合模板 *  * @return 2017年3月26日 */@Overridepublic ZSetOperations<String, V> zSetTemplate() {return jedisTemplate.opsForZSet();}@Overridepublic 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;}@Overridepublic 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);@Overridepublic 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);}}@Overridepublic 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);}











0 0