在上一篇中springboot 2.X 集成redis中提到了在spring-boot-starter-data-redis中使用JdkSerializationRedisSerializerl来实现序列化,

这里看下具体是如何实现的。

1.RedisSerializer接口

在spring-data-redis包下,有一个RedisSerializer接口,提供了序列化和反序列化的基本接口。

public interface RedisSerializer<T> {

	/**
* Serialize the given object to binary data.
*
* @param t object to serialize. Can be {@literal null}.
* @return the equivalent binary data. Can be {@literal null}.
*/
@Nullable
byte[] serialize(@Nullable T t) throws SerializationException; /**
* Deserialize an object from the given binary data.
*
* @param bytes object binary representation. Can be {@literal null}.
* @return the equivalent object instance. Can be {@literal null}.
*/
@Nullable
T deserialize(@Nullable byte[] bytes) throws SerializationException; /**
* Obtain a {@link RedisSerializer} using java serialization.<br />
* <strong>Note:</strong> Ensure that your domain objects are actually {@link java.io.Serializable serializable}.
*
* @return never {@literal null}.
* @since 2.1
*/
static RedisSerializer<Object> java() {
return java(null);
} /**
* Obtain a {@link RedisSerializer} using java serialization with the given {@link ClassLoader}.<br />
* <strong>Note:</strong> Ensure that your domain objects are actually {@link java.io.Serializable serializable}.
*
* @param classLoader the {@link ClassLoader} to use for deserialization. Can be {@literal null}.
* @return new instance of {@link RedisSerializer}. Never {@literal null}.
* @since 2.1
*/
static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
return new JdkSerializationRedisSerializer(classLoader);
} /**
* Obtain a {@link RedisSerializer} that can read and write JSON using
* <a href="https://github.com/FasterXML/jackson-core">Jackson</a>.
*
* @return never {@literal null}.
* @since 2.1
*/
static RedisSerializer<Object> json() {
return new GenericJackson2JsonRedisSerializer();
} /**
* Obtain a simple {@link java.lang.String} to {@literal byte[]} (and back) serializer using
* {@link java.nio.charset.StandardCharsets#UTF_8 UTF-8} as the default {@link java.nio.charset.Charset}.
*
* @return never {@literal null}.
* @since 2.1
*/
static RedisSerializer<String> string() {
return StringRedisSerializer.UTF_8;
}
}

可以看到byte[] serialize(@Nullable T t)和T deserialize(@Nullable byte[] bytes)就是序列化和反序列化接口,并且下面还定义了java的JdkSerializationRedisSerializer序列化、json的GenericJackson2JsonRedisSerializer和string的StringRedisSerializer.UTF_8.

2.1 JdkSerializationRedisSerializer序列化

public class JdkSerializationRedisSerializer implements RedisSerializer<Object> {

	private final Converter<Object, byte[]> serializer;
private final Converter<byte[], Object> deserializer; /**
* Creates a new {@link JdkSerializationRedisSerializer} using the default class loader.
*/
public JdkSerializationRedisSerializer() {
this(new SerializingConverter(), new DeserializingConverter());
} /**
* Creates a new {@link JdkSerializationRedisSerializer} using a {@link ClassLoader}.
*
* @param classLoader the {@link ClassLoader} to use for deserialization. Can be {@literal null}.
* @since 1.7
*/
public JdkSerializationRedisSerializer(@Nullable ClassLoader classLoader) {
this(new SerializingConverter(), new DeserializingConverter(classLoader));
} /**
* Creates a new {@link JdkSerializationRedisSerializer} using a {@link Converter converters} to serialize and
* deserialize objects.
*
* @param serializer must not be {@literal null}
* @param deserializer must not be {@literal null}
* @since 1.7
*/
public JdkSerializationRedisSerializer(Converter<Object, byte[]> serializer, Converter<byte[], Object> deserializer) { Assert.notNull(serializer, "Serializer must not be null!");
Assert.notNull(deserializer, "Deserializer must not be null!"); this.serializer = serializer;
this.deserializer = deserializer;
} public Object deserialize(@Nullable byte[] bytes) { if (SerializationUtils.isEmpty(bytes)) {
return null;
} try {
return deserializer.convert(bytes);
} catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
} @Override
public byte[] serialize(@Nullable Object object) {
if (object == null) {
return SerializationUtils.EMPTY_ARRAY;
}
try {
return serializer.convert(object);
} catch (Exception ex) {
throw new SerializationException("Cannot serialize", ex);
}
}
}

在JdkSerializationRedisSerializer构造方法中,传入了Converter的两个对象,serialize的序列化就使用SerializingConverter的convert方法

public byte[] convert(Object source) {
try {
return this.serializer.serializeToByteArray(source);
}
catch (Throwable ex) {
throw new SerializationFailedException("Failed to serialize object using " +
this.serializer.getClass().getSimpleName(), ex);
}
}

Serializer 接口

void serialize(T object, OutputStream outputStream) throws IOException;

default byte[] serializeToByteArray(T object) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
serialize(object, out);
return out.toByteArray();
}

在这里JdkSerializationRedisSerializer中,使用的是DefaultSerializer,它实现了serialize方法:

public class DefaultSerializer implements Serializer<Object> {

	/**
* Writes the source object to an output stream using Java serialization.
* The source object must implement {@link Serializable}.
* @see ObjectOutputStream#writeObject(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();
} }

可以看到使用了ObjectOutputStream的writeObject方法来实现的,下面会继续调用writeObject0方法,相关可以查看ObjectOutputStream的序列化和反序列化

JdkSerializationRedisSerializer的反序列化方式转化类型有区别,这里就不详细介绍了。

2.2 GenericJackson2JsonRedisSerializer序列化

GenericJackson2JsonRedisSerializer主要使用ObjectMapper来实现。

@Override
public byte[] serialize(@Nullable Object source) throws SerializationException { if (source == null) {
return SerializationUtils.EMPTY_ARRAY;
} try {
return mapper.writeValueAsBytes(source);
} catch (JsonProcessingException e) {
throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
}
} @Override
public Object deserialize(@Nullable byte[] source) throws SerializationException {
return deserialize(source, Object.class);
}
public <T> T deserialize(@Nullable byte[] source, Class<T> type) throws SerializationException { Assert.notNull(type,
"Deserialization type must not be null! Please provide Object.class to make use of Jackson2 default typing."); if (SerializationUtils.isEmpty(source)) {
return null;
} try {
return mapper.readValue(source, type);
} catch (Exception ex) {
throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
}
}

查看writeValueAsBytes方法,并且继续向下,可以看到使用了jackson相关包进行json化数据。

private final void _serialize(JsonGenerator gen, Object value,
JsonSerializer<Object> ser, PropertyName rootName)
throws IOException
{
try {
gen.writeStartObject();
gen.writeFieldName(rootName.simpleAsEncoded(_config));
ser.serialize(value, gen, this);
gen.writeEndObject();
} catch (Exception e) {
throw _wrapAsIOE(gen, e);
}
}

2.3 StringRedisSerializer

StringRedisTemplate中使用了UTF_8的编码格式。

public class StringRedisSerializer implements RedisSerializer<String> {

	private final Charset charset;

	/**
* {@link StringRedisSerializer} to use 7 bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode
* character set.
*
* @see StandardCharsets#US_ASCII
* @since 2.1
*/
public static final StringRedisSerializer US_ASCII = new StringRedisSerializer(StandardCharsets.US_ASCII); /**
* {@link StringRedisSerializer} to use ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
*
* @see StandardCharsets#ISO_8859_1
* @since 2.1
*/
public static final StringRedisSerializer ISO_8859_1 = new StringRedisSerializer(StandardCharsets.ISO_8859_1); /**
* {@link StringRedisSerializer} to use 8 bit UCS Transformation Format.
*
* @see StandardCharsets#UTF_8
* @since 2.1
*/
public static final StringRedisSerializer UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8); /**
* Creates a new {@link StringRedisSerializer} using {@link StandardCharsets#UTF_8 UTF-8}.
*/
public StringRedisSerializer() {
this(StandardCharsets.UTF_8);
} /**
* Creates a new {@link StringRedisSerializer} using the given {@link Charset} to encode and decode strings.
*
* @param charset must not be {@literal null}.
*/
public StringRedisSerializer(Charset charset) { Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
} /*
* (non-Javadoc)
* @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[])
*/
@Override
public String deserialize(@Nullable byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
} /*
* (non-Javadoc)
* @see org.springframework.data.redis.serializer.RedisSerializer#serialize(java.lang.Object)
*/
@Override
public byte[] serialize(@Nullable String string) {
return (string == null ? null : string.getBytes(charset));
} @Override
public Class<?> getTargetType() {
return String.class;
}
}

当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,可以使用这种方式,非常简便。

谈谈spring-boot-starter-data-redis序列化的更多相关文章

  1. spring -boot s-tarter 详解

    Starter POMs是可以包含到应用中的一个方便的依赖关系描述符集合.你可以获取所有Spring及相关技术的一站式服务,而不需要翻阅示例代码,拷贝粘贴大量的依赖描述符.例如,如果你想使用Sprin ...

  2. SpringBoot 之Spring Boot Starter依赖包及作用

    Spring Boot 之Spring Boot Starter依赖包及作用 spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. spri ...

  3. Spring Boot Starter列表

    转自:http://blog.sina.com.cn/s/blog_798f713f0102wiy5.html Spring Boot Starter 基本的一共有43种,具体如下: 1)spring ...

  4. 【spring boot】【redis】spring boot 集成redis的发布订阅机制

    一.简单介绍 1.redis的发布订阅功能,很简单. 消息发布者和消息订阅者互相不认得,也不关心对方有谁. 消息发布者,将消息发送给频道(channel). 然后是由 频道(channel)将消息发送 ...

  5. Spring Boot 2整合Redis做缓存

    既然是要用Redis做缓存,自然少不了安装了.但是本文主要讲Spring Boot与Redis整合.安装教程请另行百度! 1.首先是我们的Redis配置类 package com.tyc; impor ...

  6. 【spring boot】【redis】spring boot基于redis的LUA脚本 实现分布式锁

    spring boot基于redis的LUA脚本 实现分布式锁[都是基于redis单点下] 一.spring boot 1.5.X 基于redis 的 lua脚本实现分布式锁 1.pom.xml &l ...

  7. Spring Boot Starter 介绍

    http://www.baeldung.com/spring-boot-starters 作者:baeldung 译者:http://oopsguy.com 1.概述 依赖管理是任何复杂项目的关键部分 ...

  8. Spring Boot (一): Spring Boot starter自定义

    前些日子在公司接触了spring boot和spring cloud,有感于其大大简化了spring的配置过程,十分方便使用者快速构建项目,而且拥有丰富的starter供开发者使用.但是由于其自动化配 ...

  9. Spring Boot + MyBatis + Druid + Redis + Thymeleaf 整合小结

    Spring Boot + MyBatis + Druid + Redis + Thymeleaf 整合小结 这两天闲着没事想利用**Spring Boot**加上阿里的开源数据连接池**Druid* ...

  10. spring boot 中使用redis session

    spring boot 默认的httpsession是存在内存中.这种默认方式有几个缺点:1.当分布式部署时,存在session不一致的问题:2.当服务重启时session就会丢失,这时候用户就需要重 ...

随机推荐

  1. JAVA课程学习感想

    JAVA课程学习感想 在学习JAVA之前,我们学习了C语言,汇编语言,数据结构等等.虽然学习了这些,但对于JAVA来说,学习起来不是那么容易,所有的计算机语言有相似的地方,但他们更有不同的地方.对我来 ...

  2. MySQL8.0 忘记密码、重置密码

    修改my.cnf [mysqld] 域中添加skip-grant-tables 重启mysqld服务 systemctl restart mysqld 重新使用空密码登录,直接敲回车 mysql -u ...

  3. 一个 json 转换工具

    在前后端的数据协议(主要指http和websocket)的问题上,如果前期沟通好了,那么数据协议上问题会很好解决,前后端商议一种都可以接受的格式即可.但是如果接入的是老系统.第三方系统,或者由于某些奇 ...

  4. Netty学习笔记(二) - ChannelPipeline和ChannelHandler

    ChannelPipeline 和 ChannelHandler 是 Netty 重要的组件之一,通过这篇文章,重点了解这些组件是如何驱动数据流动和处理的. 一.ChannelHandler 在上一篇 ...

  5. 50个SQL语句(MySQL版) 问题十三

    --------------------------表结构-------------------------- student(StuId,StuName,StuAge,StuSex) 学生表 tea ...

  6. Golang模拟用户登陆,突破教务系统

    目录 一.Golang模拟用户登陆,突破教务系统 1.1 请求登陆页面 1.2 抓包分析登陆请求 1.3 golang使用js引擎合成salt 1.4 模拟表单提交,完成登陆 1.5 进入成绩查询页, ...

  7. Java实现k个数乘(cheng)(自然数的k乘积问题)

    k个数乘(cheng) 题目描述 桐桐想把一个自然数N分解成K个大于l的自然数相乘的形式,要求这K个数按从小到大排列,而且除了第K个数之外,前面(K-l)个数是N分解出来的最小自然数.例如:N=24, ...

  8. java实现第五届蓝桥杯排列序数

    排列序数 如果用a b c d这4个字母组成一个串,有4!=24种,如果把它们排个序,每个串都对应一个序号: abcd 0 abdc 1 acbd 2 acdb 3 adbc 4 adcb 5 bac ...

  9. OC语言-NSMutableArray为什么要用strong来修饰

    Talk is cheap show you my code!  NSMutableArray属性为什么要用strong来修饰,其实就是一个深复制和浅复制的问题. <pre name=" ...

  10. SmokePing 快速搭建

    SmokePing介绍 smokeping是来监控IDC机房网络质量情况,可以从监控图上的延时与丢包情况分辨出机房的网络是否稳定,是否为多线,是否为BGP机房以及到各城市的三个运行商网络各是什么情况. ...