spring-data-redis 整合,以及使用kryo序列化代替jdk原生序列化机制
2017-04-02 12:10
991 查看
之前一直没使用spring-data-redis模板进行redis操作,周日闲着没事,整合了下,又想不适用jdk原生的序列化,于是自己简单的,参考网上的,后期路过的坑,修改了下,
实验发现,kryo还是不适合作为 持久化的序列化使用的, kryo序列化仅做参考吧
引入 spring-data-redis maven依赖
上配置,自己简单看看源码,就知道配置什么意思了,
下面开始贴出来简单封装的模板先贴实现类,遇到的坑已经写上注释了
下面是接口
然后最后是kryo的序列化实现
ok完毕
/**
* 空byte数组
*/
public static final byte[] EMPTY_ARRAY = new byte[0];
实验发现,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); }
相关文章推荐
- jedis,spring-redis-data 整合使用,版本问题异常以及解决。
- spring-data-redis使用jdk序列化时increment的异常
- org.springframework.data.redis.serializer.JdkSerializationRedisSerializer序列化工具
- springboot使用protostuff进行序列化和反序列化整合redis的redisTemplate的各种方法的写法
- spring 整合 redis,以及spring的RedisTemplate如何使用
- spring-data-redis 使用过程中需要注意的一点(序列化选择)
- 使用kryo作为spring data redis的序列化器
- spring 整合 redis,以及spring的RedisTemplate如何使用
- springboot学习笔记(三)使用JDBC以及整合spring data jpa
- spring 整合 redis,以及spring的RedisTemplate如何使用
- dubbo2.5-spring4-mybastis3.2-springmvc4-mongodb3.4-redis3.2整合(五)Spring中spring-data-redis的使用
- spring 整合 redis,以及spring的RedisTemplate如何使用
- spring 整合 redis,以及spring的RedisTemplate如何使用
- spring-data-redis 使用 protobuf进行序列化和反序列
- jedis,spring-redis-data 整合使用,版本问题异常
- spring 整合 redis,以及spring的RedisTemplate如何使用
- 深入理解Spring Redis的使用 (七)、Spring Redis 使用 jackson序列化 以及 BaseDao代码
- spring-data-redis与Jedis整合使用
- spring-data-redis整合以及基本操作
- spring 整合 redis,以及spring的RedisTemplate如何使用