在上一篇中 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 数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候, 可以使用这种方式, 非常简便.
来源: https://www.cnblogs.com/homeSicker/p/13178281.html