REDIS学习(4)spring boot redisTemplate 对REDIS的简单封装,以及对引用包的说明,以及对序列化的详细说明
2016-08-10 17:28
871 查看
综合1,2,3以及目前,我们所引用的redis包不过是
添加进来后
引用包至少有
spring-boot-starter-redis-1.3.5.RELEASE.jar
spring-data-redis-1.6.4.RELEASE.jar
jedis-2.7.3.jar
三个包
结合前面的第三节,redis都是跟Spring一起做为通用缓存接口使用
这一节使用的redisTemplate更像是一个数据库的操作
使用:
根据上一节内容,我们知道如果没有指定RedisTemplate,spring redis cache会选用javaAPI的序列化方式来将对象序列化,这种序列化方式性能一般,切后面增加字段会造成麻烦,我觉的比较合适的序列化方式有protocol buffer,JSON,带有递归的二进制字节流的方式等。
我们下面详细分析RedisTempalte这个类,StringRedisTemplate是RedisTemplate的唯一子类。
这个类很简单,我们甚至可以仿照此方法定义自己的MyRedisTemplate
[API]
RedisTemplate默认定义了两个常用的序列化类
private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();
以及 private RedisSerializer<String> stringSerializer = new StringRedisSerializer();
我们可以如下注入我们的RedisTemplate,下面的例子将key的序列化方式定义为字符串,将value的序列化使用了jackson
最后我们看一下Spring data redis定义的序列化接口和默认的JDK序列化的封装,代码比较整洁,我们可以从中学习
[API]
[API]
[API]
[API]
[API]序列化writeObject
public class DefaultSerializer implements Serializer<Object> {
@Override
public void serialize(Object object, OutputStream outputStream) throws IOException {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
}
}
[API]反序列化是用类加载器
public class DefaultDeserializer implements Deserializer<Object> {
private final ClassLoader classLoader;
public DefaultDeserializer() {
this.classLoader = null;
}
<span style="color:#ff0000;"> public DefaultDeserializer(ClassLoader classLoader) {
this.classLoader = classLoader;
}</span>
@Override
@SuppressWarnings("resource")
public Object deserialize(InputStream inputStream) throws IOException {
ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
try {
return objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
}
}
<dependency> <groupId>org.springframework.boot</groupId><!-- 会附带引进jedis-2.7.3的包 --> <artifactId>spring-boot-starter-redis</artifactId> </dependency>
添加进来后
引用包至少有
spring-boot-starter-redis-1.3.5.RELEASE.jar
spring-data-redis-1.6.4.RELEASE.jar
jedis-2.7.3.jar
三个包
结合前面的第三节,redis都是跟Spring一起做为通用缓存接口使用
这一节使用的redisTemplate更像是一个数据库的操作
@Service public class RedisService { @Autowired RedisTemplate<?, ?> redisTemplate; /**获得客户端列表 */ public List<?> getClients(){ return redisTemplate.getClientList(); } /**设置有超时时间的KV */ public Long set(String key, String value, long seconds) { return redisTemplate.execute(c -> { c.set(key.getBytes(), value.getBytes()); c.expire(key.getBytes(), seconds); return 1L; }); } /** *存入不会超时的KV */ public Long set(String key, String value) { return redisTemplate.execute(c -> { c.set(key.getBytes(), value.getBytes()); return 1L; }); } /** * redis数据库条数 */ public Long dbSize() { return redisTemplate.execute(c -> c.dbSize()); } public String ping() { return redisTemplate.execute(c -> c.ping()); } /** * 删除所有指定数据库的数据 */ public long flushDB() { return redisTemplate.execute(c -> { c.flushDb(); return 1L; }); } /**判断redis数据库是否有对应的key*/ public boolean exist(String key){ return redisTemplate.execute(c->c.exists(key.getBytes())); } /**获得redis数据库所有的key*/ public Set<String> keys(String pattern){ return redisTemplate.execute(c->c.keys(pattern.getBytes()).stream().map(this::getUTF).collect(Collectors.toSet())); } private String getUTF(byte[] data){ try { return new String(data, "utf-8"); } catch (UnsupportedEncodingException e) { LogCore.BASE.error("parse bytes err:{}", e); return null; } } }
使用:
@SuppressWarnings({ "unchecked", "rawtypes" }) public long save(UserInfo usrInfo) { return redisTemplate.execute(c -> { RedisSerializer key_slz = redisTemplate.getKeySerializer(); RedisSerializer slz = redisTemplate.getValueSerializer(); LogCore.BASE.info("key_slz={},slz={}",key_slz.getClass().getSimpleName(),slz.getClass().getSimpleName()); c.set( key_slz.serialize(usrInfo.getClass().getSimpleName() + ":" + usrInfo.no), slz.serialize(usrInfo)); return 1L; }); } @SuppressWarnings({ "rawtypes", "unchecked" }) public UserInfo get(String no) { return (UserInfo) redisTemplate.execute(c -> { RedisSerializer key_slz = redisTemplate.getKeySerializer(); RedisSerializer slz = redisTemplate.getValueSerializer(); return slz.deserialize(c.get(key_slz.serialize(UserInfo.class.getSimpleName() + ":" + no))); }); }
根据上一节内容,我们知道如果没有指定RedisTemplate,spring redis cache会选用javaAPI的序列化方式来将对象序列化,这种序列化方式性能一般,切后面增加字段会造成麻烦,我觉的比较合适的序列化方式有protocol buffer,JSON,带有递归的二进制字节流的方式等。
我们下面详细分析RedisTempalte这个类,StringRedisTemplate是RedisTemplate的唯一子类。
这个类很简单,我们甚至可以仿照此方法定义自己的MyRedisTemplate
[API]
public class StringRedisTemplate extends RedisTemplate<String, String> { public StringRedisTemplate() { RedisSerializer<String> stringSerializer = new StringRedisSerializer(); setKeySerializer(stringSerializer); setValueSerializer(stringSerializer); setHashKeySerializer(stringSerializer); setHashValueSerializer(stringSerializer); } public StringRedisTemplate(RedisConnectionFactory connectionFactory) { this(); setConnectionFactory(connectionFactory); afterPropertiesSet(); } protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) { return new DefaultStringRedisConnection(connection); } }注意,子类的构造方法总会默认调用父类的无参构造方法。
RedisTemplate默认定义了两个常用的序列化类
private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();
以及 private RedisSerializer<String> stringSerializer = new StringRedisSerializer();
我们可以如下注入我们的RedisTemplate,下面的例子将key的序列化方式定义为字符串,将value的序列化使用了jackson
@Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Bean public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) { RedisCacheManager manager = new RedisCacheManager(redisTemplate); return manager; } @Bean public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(connectionFactory); setMySerializer(template); template.afterPropertiesSet(); LogCore.BASE.info("template{}" ,ReflectionToStringBuilder.toString(template, ToStringStyle.SHORT_PREFIX_STYLE)); return template; } /** * 设置序列化方法 */ private void setMySerializer(RedisTemplate template) { Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>( Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setKeySerializer(template.getStringSerializer()); template.setValueSerializer(jackson2JsonRedisSerializer); } @Bean public KeyGenerator smpkeyGenerator() { return (target, method, params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getSimpleName()).append(":");//执行方法所在的类 sb.append(Stream.of(params).map(String::valueOf).collect(Collectors.joining("_"))); return sb.toString(); }; } }
最后我们看一下Spring data redis定义的序列化接口和默认的JDK序列化的封装,代码比较整洁,我们可以从中学习
[API]
public interface RedisSerializer<T> { byte[] serialize(T t) throws SerializationException; T deserialize(byte[] bytes) throws SerializationException; }[API]
public class JdkSerializationRedisSerializer implements RedisSerializer<Object> { private Converter<Object, byte[]> serializer = new SerializingConverter(); private Converter<byte[], Object> deserializer = new DeserializingConverter(); public Object deserialize(byte[] bytes) { if (SerializationUtils.isEmpty(bytes)) { return null; } try { return deserializer.convert(bytes); } catch (Exception ex) { throw new SerializationException("Cannot deserialize", ex); } } public byte[] serialize(Object object) { if (object == null) { return SerializationUtils.EMPTY_ARRAY; } try { return serializer.convert(object); } catch (Exception ex) { throw new SerializationException("Cannot serialize", ex); } } }
[API]
public interface Converter<S, T> { T convert(S source); }
[API]
public class SerializingConverter implements Converter<Object, byte[]> { private final Serializer<Object> serializer; public SerializingConverter() { this.serializer = new DefaultSerializer(); } public SerializingConverter(Serializer<Object> serializer) { Assert.notNull(serializer, "Serializer must not be null"); this.serializer = serializer; } @Override public byte[] convert(Object source) { ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024); try { this.serializer.serialize(source, byteStream); return byteStream.toByteArray(); } catch (Throwable ex) { throw new SerializationFailedException("Failed to serialize object using " + this.serializer.getClass().getSimpleName(), ex); } } }
[API]
public class DeserializingConverter implements Converter<byte[], Object> { private final Deserializer<Object> deserializer; public DeserializingConverter() { this.deserializer = new DefaultDeserializer(); } public DeserializingConverter(ClassLoader classLoader) { this.deserializer = new DefaultDeserializer(classLoader); } public DeserializingConverter(Deserializer<Object> deserializer) { Assert.notNull(deserializer, "Deserializer must not be null"); this.deserializer = deserializer; } @Override public Object convert(byte[] source) { ByteArrayInputStream byteStream = new ByteArrayInputStream(source); try { return this.deserializer.deserialize(byteStream); } catch (Throwable ex) { throw new SerializationFailedException("Failed to deserialize payload. " + "Is the byte array a result of corresponding serialization for " + this.deserializer.getClass().getSimpleName() + "?", ex); } } }
[API]序列化writeObject
public class DefaultSerializer implements Serializer<Object> {
@Override
public void serialize(Object object, OutputStream outputStream) throws IOException {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
}
}
[API]反序列化是用类加载器
public class DefaultDeserializer implements Deserializer<Object> {
private final ClassLoader classLoader;
public DefaultDeserializer() {
this.classLoader = null;
}
<span style="color:#ff0000;"> public DefaultDeserializer(ClassLoader classLoader) {
this.classLoader = classLoader;
}</span>
@Override
@SuppressWarnings("resource")
public Object deserialize(InputStream inputStream) throws IOException {
ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
try {
return objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
}
}
相关文章推荐
- Spring Boot整合集成StringRedisTemplate的简单记录
- RedisTemplate的使用说明(序列化以及事物)
- spring boot RedisTemplate的简单使用
- spring boot data RedisTemplate 序列化问题
- Spring RedisTemplate操作-序列化操作
- spring-boot 速成(12) - 如何注入多个redis StringRedisTemplate
- spring boot使用redisTemplate存储键值出现乱码
- jedis与spring整合及简单的使用RedisTemplate操作
- Spring Redis 序列化方式修改——RedisTemplate存取数据异常,在数据前有一串字符
- Spring Boot StringRedisTemplate常用操作
- 关于springboot整合redis(使用RedisTemplate操作redis)
- SpringBoot RedisTemplate乱码解决方案
- spring boot 自学笔记(三) Redis集成—RedisTemplate
- Spring RedisTemplate操作-序列化性能测试(12)
- Springboot RedisTemplate 报No qualifying bean of type... 不能按类型装配注入
- spring整合redis以及使用RedisTemplate的方法
- jedis与spring整合及简单的使用RedisTemplate操作
- Spring RedisTemplate操作-序列化性能测试(12)
- Spring包结构以及各个包之间引用关系说明
- spring中redistemplate不能用通配符keys查出相应Key的问题