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

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

1.RedisSerializer接口

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

  1. public interface RedisSerializer<T> {
  2. /**
  3. * Serialize the given object to binary data.
  4. *
  5. * @param t object to serialize. Can be {@literal null}.
  6. * @return the equivalent binary data. Can be {@literal null}.
  7. */
  8. @Nullable
  9. byte[] serialize(@Nullable T t) throws SerializationException;
  10. /**
  11. * Deserialize an object from the given binary data.
  12. *
  13. * @param bytes object binary representation. Can be {@literal null}.
  14. * @return the equivalent object instance. Can be {@literal null}.
  15. */
  16. @Nullable
  17. T deserialize(@Nullable byte[] bytes) throws SerializationException;
  18. /**
  19. * Obtain a {@link RedisSerializer} using java serialization.<br />
  20. * <strong>Note:</strong> Ensure that your domain objects are actually {@link java.io.Serializable serializable}.
  21. *
  22. * @return never {@literal null}.
  23. * @since 2.1
  24. */
  25. static RedisSerializer<Object> java() {
  26. return java(null);
  27. }
  28. /**
  29. * Obtain a {@link RedisSerializer} using java serialization with the given {@link ClassLoader}.<br />
  30. * <strong>Note:</strong> Ensure that your domain objects are actually {@link java.io.Serializable serializable}.
  31. *
  32. * @param classLoader the {@link ClassLoader} to use for deserialization. Can be {@literal null}.
  33. * @return new instance of {@link RedisSerializer}. Never {@literal null}.
  34. * @since 2.1
  35. */
  36. static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
  37. return new JdkSerializationRedisSerializer(classLoader);
  38. }
  39. /**
  40. * Obtain a {@link RedisSerializer} that can read and write JSON using
  41. * <a href="https://github.com/FasterXML/jackson-core">Jackson</a>.
  42. *
  43. * @return never {@literal null}.
  44. * @since 2.1
  45. */
  46. static RedisSerializer<Object> json() {
  47. return new GenericJackson2JsonRedisSerializer();
  48. }
  49. /**
  50. * Obtain a simple {@link java.lang.String} to {@literal byte[]} (and back) serializer using
  51. * {@link java.nio.charset.StandardCharsets#UTF_8 UTF-8} as the default {@link java.nio.charset.Charset}.
  52. *
  53. * @return never {@literal null}.
  54. * @since 2.1
  55. */
  56. static RedisSerializer<String> string() {
  57. return StringRedisSerializer.UTF_8;
  58. }
  59. }

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

2.1 JdkSerializationRedisSerializer序列化

  1. public class JdkSerializationRedisSerializer implements RedisSerializer<Object> {
  2. private final Converter<Object, byte[]> serializer;
  3. private final Converter<byte[], Object> deserializer;
  4. /**
  5. * Creates a new {@link JdkSerializationRedisSerializer} using the default class loader.
  6. */
  7. public JdkSerializationRedisSerializer() {
  8. this(new SerializingConverter(), new DeserializingConverter());
  9. }
  10. /**
  11. * Creates a new {@link JdkSerializationRedisSerializer} using a {@link ClassLoader}.
  12. *
  13. * @param classLoader the {@link ClassLoader} to use for deserialization. Can be {@literal null}.
  14. * @since 1.7
  15. */
  16. public JdkSerializationRedisSerializer(@Nullable ClassLoader classLoader) {
  17. this(new SerializingConverter(), new DeserializingConverter(classLoader));
  18. }
  19. /**
  20. * Creates a new {@link JdkSerializationRedisSerializer} using a {@link Converter converters} to serialize and
  21. * deserialize objects.
  22. *
  23. * @param serializer must not be {@literal null}
  24. * @param deserializer must not be {@literal null}
  25. * @since 1.7
  26. */
  27. public JdkSerializationRedisSerializer(Converter<Object, byte[]> serializer, Converter<byte[], Object> deserializer) {
  28. Assert.notNull(serializer, "Serializer must not be null!");
  29. Assert.notNull(deserializer, "Deserializer must not be null!");
  30. this.serializer = serializer;
  31. this.deserializer = deserializer;
  32. }
  33. public Object deserialize(@Nullable byte[] bytes) {
  34. if (SerializationUtils.isEmpty(bytes)) {
  35. return null;
  36. }
  37. try {
  38. return deserializer.convert(bytes);
  39. } catch (Exception ex) {
  40. throw new SerializationException("Cannot deserialize", ex);
  41. }
  42. }
  43. @Override
  44. public byte[] serialize(@Nullable Object object) {
  45. if (object == null) {
  46. return SerializationUtils.EMPTY_ARRAY;
  47. }
  48. try {
  49. return serializer.convert(object);
  50. } catch (Exception ex) {
  51. throw new SerializationException("Cannot serialize", ex);
  52. }
  53. }
  54. }

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

  1. public byte[] convert(Object source) {
  2. try {
  3. return this.serializer.serializeToByteArray(source);
  4. }
  5. catch (Throwable ex) {
  6. throw new SerializationFailedException("Failed to serialize object using " +
  7. this.serializer.getClass().getSimpleName(), ex);
  8. }
  9. }

Serializer 接口

  1. void serialize(T object, OutputStream outputStream) throws IOException;
  2. default byte[] serializeToByteArray(T object) throws IOException {
  3. ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
  4. serialize(object, out);
  5. return out.toByteArray();
  6. }

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

  1. public class DefaultSerializer implements Serializer<Object> {
  2. /**
  3. * Writes the source object to an output stream using Java serialization.
  4. * The source object must implement {@link Serializable}.
  5. * @see ObjectOutputStream#writeObject(Object)
  6. */
  7. @Override
  8. public void serialize(Object object, OutputStream outputStream) throws IOException {
  9. if (!(object instanceof Serializable)) {
  10. throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
  11. "but received an object of type [" + object.getClass().getName() + "]");
  12. }
  13. ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
  14. objectOutputStream.writeObject(object);
  15. objectOutputStream.flush();
  16. }
  17. }

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

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

2.2 GenericJackson2JsonRedisSerializer序列化

GenericJackson2JsonRedisSerializer主要使用ObjectMapper来实现。

  1. @Override
  2. public byte[] serialize(@Nullable Object source) throws SerializationException {
  3. if (source == null) {
  4. return SerializationUtils.EMPTY_ARRAY;
  5. }
  6. try {
  7. return mapper.writeValueAsBytes(source);
  8. } catch (JsonProcessingException e) {
  9. throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
  10. }
  11. }
  12. @Override
  13. public Object deserialize(@Nullable byte[] source) throws SerializationException {
  14. return deserialize(source, Object.class);
  15. }
  16. public <T> T deserialize(@Nullable byte[] source, Class<T> type) throws SerializationException {
  17. Assert.notNull(type,
  18. "Deserialization type must not be null! Please provide Object.class to make use of Jackson2 default typing.");
  19. if (SerializationUtils.isEmpty(source)) {
  20. return null;
  21. }
  22. try {
  23. return mapper.readValue(source, type);
  24. } catch (Exception ex) {
  25. throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
  26. }
  27. }

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

  1. private final void _serialize(JsonGenerator gen, Object value,
  2. JsonSerializer<Object> ser, PropertyName rootName)
  3. throws IOException
  4. {
  5. try {
  6. gen.writeStartObject();
  7. gen.writeFieldName(rootName.simpleAsEncoded(_config));
  8. ser.serialize(value, gen, this);
  9. gen.writeEndObject();
  10. } catch (Exception e) {
  11. throw _wrapAsIOE(gen, e);
  12. }
  13. }

2.3 StringRedisSerializer

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

  1. public class StringRedisSerializer implements RedisSerializer<String> {
  2. private final Charset charset;
  3. /**
  4. * {@link StringRedisSerializer} to use 7 bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode
  5. * character set.
  6. *
  7. * @see StandardCharsets#US_ASCII
  8. * @since 2.1
  9. */
  10. public static final StringRedisSerializer US_ASCII = new StringRedisSerializer(StandardCharsets.US_ASCII);
  11. /**
  12. * {@link StringRedisSerializer} to use ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
  13. *
  14. * @see StandardCharsets#ISO_8859_1
  15. * @since 2.1
  16. */
  17. public static final StringRedisSerializer ISO_8859_1 = new StringRedisSerializer(StandardCharsets.ISO_8859_1);
  18. /**
  19. * {@link StringRedisSerializer} to use 8 bit UCS Transformation Format.
  20. *
  21. * @see StandardCharsets#UTF_8
  22. * @since 2.1
  23. */
  24. public static final StringRedisSerializer UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);
  25. /**
  26. * Creates a new {@link StringRedisSerializer} using {@link StandardCharsets#UTF_8 UTF-8}.
  27. */
  28. public StringRedisSerializer() {
  29. this(StandardCharsets.UTF_8);
  30. }
  31. /**
  32. * Creates a new {@link StringRedisSerializer} using the given {@link Charset} to encode and decode strings.
  33. *
  34. * @param charset must not be {@literal null}.
  35. */
  36. public StringRedisSerializer(Charset charset) {
  37. Assert.notNull(charset, "Charset must not be null!");
  38. this.charset = charset;
  39. }
  40. /*
  41. * (non-Javadoc)
  42. * @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[])
  43. */
  44. @Override
  45. public String deserialize(@Nullable byte[] bytes) {
  46. return (bytes == null ? null : new String(bytes, charset));
  47. }
  48. /*
  49. * (non-Javadoc)
  50. * @see org.springframework.data.redis.serializer.RedisSerializer#serialize(java.lang.Object)
  51. */
  52. @Override
  53. public byte[] serialize(@Nullable String string) {
  54. return (string == null ? null : string.getBytes(charset));
  55. }
  56. @Override
  57. public Class<?> getTargetType() {
  58. return String.class;
  59. }
  60. }

当你的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. 几种常见的app推广形式

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  2. hackone ssrf

    alyssa_herrera submitted a report to U.S. Dept Of Defense. Jan 29th (2 years ago) Summary:A server s ...

  3. PYTHON 黑帽子第二章总结

    基于python3编写 import sys, socket, getopt, threading, argparse, subprocess # globals options listen = F ...

  4. Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)部分(A~E)题解

    (A) Even Subset Sum Problem 题解:因为n非常非常小,直接暴力枚举所有区间即可. #include<bits/stdc++.h> using namespace ...

  5. 居然还有人这样解说mybatis运行原理

    目录 Mybatis基本认识 动态代理 JDK实现 CGLIB动态代理 总结 反射 Configuration对象作用 映射器结构 sqlsession执行流程(源码跟踪) Executor Stat ...

  6. Java实现 LeetCode 575 分糖果(看看是你的长度小还是我的种类少)

    575. 分糖果 给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果.你需要把这些糖果平均分给一个弟弟和一个妹妹.返回妹妹可以获得的最大糖果的种类数. 示例 1: 输入 ...

  7. Java实现 蓝桥杯 算法提高 最大乘积

    算法提高 最大乘积 时间限制:1.0s 内存限制:512.0MB 提交此题 问题描述 对于n个数,从中取出m个数,如何取使得这m个数的乘积最大呢? 输入格式 第一行一个数表示数据组数 每组输入数据共2 ...

  8. Java实现 蓝桥杯VIP 算法训练 王后传说

    问题描述 地球人都知道,在国际象棋中,后如同太阳,光芒四射,威风八面,它能控制横.坚.斜线位置. 看过清宫戏的中国人都知道,后宫乃步步惊心的险恶之地.各皇后都有自己的势力范围,但也总能找到相安无事的办 ...

  9. Java实现 LeetCode 392 判断子序列

    392. 判断子序列 给定字符串 s 和 t ,判断 s 是否为 t 的子序列. 你可以认为 s 和 t 中仅包含英文小写字母.字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符 ...

  10. Java实现 蓝桥杯VIP 算法训练 采油区域

    算法训练 采油区域 时间限制:2.0s 内存限制:512.0MB 提交此题 查看参考代码 采油区域 Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井.被拍卖的整 ...