在上一篇中springboot 2.X 集成redis中提到了在spring-boot-starter-data-redis中使用JdkSerializationRedisSerializerl來實現序列化,
這裏看下具體是如何實現的。
1.RedisSerializer接口
在spring-data-redis包下,有一個RedisSerializer接口,提供了序列化和反序列化的基本接口。
html
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序列化
java
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方法git
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 接口 github
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方法:redis
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的反序列化方式轉化類型有區別,這裏就不詳細介紹了。
spring
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化數據。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的編碼格式。
springboot
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數據庫裏面原本存的是字符串數據或者你要存取的數據就是字符串類型數據的時候,可使用這種方式,很是簡便。app