1.redis序列化器作用
- 在保存數據時需要把java對象序列化爲byte,在讀取數據時需要把byte反序列化爲java對象;
- 不同的java數據類型序列化和反序列化的邏輯不一樣;
- java對象序列化後的文本格式不一樣。常見的有java對象字節碼、json字符串,xml字符串;
- spring把上述邏輯封閉在redis序列化器中,接口爲RedisSerializer;
2.redis序列化器結構
3.序列化器解析
3.1.RedisSerializer接口
- 提供了序列化serialize和反序列化deserialize兩個接口;
- 提供了幾個靜態方法,每個靜態方法針對不同java對象序列化後的文本格式;
- 提供了getTargetType和canSerialize兩個接口,提供此序列化器針對的數據類型;
//**把對象序列化爲byte數組
byte[] serialize(@Nullable T t) throws SerializationException;
//**把byte數組反序列化爲對象
T deserialize(@Nullable byte[] bytes) throws SerializationException;
//**靜態方法,java格式序列化器
static RedisSerializer<Object> java() {
return java(null);
}
//**靜態方法,java格式序列化器
static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
return new JdkSerializationRedisSerializer(classLoader);
}
//**靜態方法,json格式序列化器
static RedisSerializer<Object> json() {
return new GenericJackson2JsonRedisSerializer();
}
//**靜態方法,string數據類型序列化器
static RedisSerializer<String> string() {
return StringRedisSerializer.UTF_8;
}
//**靜態方法,byte數據類型序列化器
static RedisSerializer<byte[]> byteArray() {
return ByteArrayRedisSerializer.INSTANCE;
}
//**檢查是此序列化器否能夠序列化指定數據類型
default boolean canSerialize(Class<?> type) {
return ClassUtils.isAssignable(getTargetType(), type);
}
//**此序列化器針對的數據類型,默認object
default Class<?> getTargetType() {
return Object.class;
}
3.2.ByteArrayRedisSerializer
- 一個枚舉類型,針對byte數據類型;
- redis最終保存的就是byte數據類型,所有此類的serialize和deserialize什麼都沒幹,直接返回數據;
3.3.StringRedisSerializer
//**字符集
private final Charset charset;
//**針對不同字符集的StringRedisSerializer
public static final StringRedisSerializer US_ASCII = new StringRedisSerializer(StandardCharsets.US_ASCII);
public static final StringRedisSerializer ISO_8859_1 = new StringRedisSerializer(StandardCharsets.ISO_8859_1);
public static final StringRedisSerializer UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);
//**默認爲UTF_8字符集
public StringRedisSerializer() {
this(StandardCharsets.UTF_8);
}
//**使用指定的字符集直接把byte轉換爲string類型
@Override
public String deserialize(@Nullable byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
//**使用指定的字符集直接把string類型轉換爲byte
@Override
public byte[] serialize(@Nullable String string) {
return (string == null ? null : string.getBytes(charset));
}
//**此序列化器針對的數據類型爲string
@Override
public Class<?> getTargetType() {
return String.class;
}
3.4.GenericToStringSerializer
- 針對object數據類型;
- 序列化時使用spring ConversionService/TypeConverter把對象轉換爲string,然後在把string轉換爲byte;
- 反序列化時把byte轉換爲string,然後使用spring ConversionService/TypeConverter把string轉換爲對象;
- 必須指定一個反序列化後的數據類型,反序列化只能生成該數據類型對象;
//**反序列化時,轉換後的java數據類型
private final Class<T> type;
//**字符轉換爲byte時的字符集
private final Charset charset;
//**默認使用DefaultConversionService
private Converter converter = new Converter(new DefaultConversionService());
//**必須指定反序列化後的java數據類型type,反序列化只能生成type數據類型的對象
public GenericToStringSerializer(Class<T> type) {
this(type, StandardCharsets.UTF_8);
}
@Override
public T deserialize(@Nullable byte[] bytes) {
...
//**把byte轉換爲string
String string = new String(bytes, charset);
//**使用converter把string轉換爲對象
return converter.convert(string, type);
}
@Override
public byte[] serialize(@Nullable T object) {
...
//**使用converter把對象轉換爲string
String string = converter.convert(object, String.class);
//**把string轉換爲byte
return string.getBytes(charset);
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// TODO: converter不會爲空,所以這段做對不會使用到
if (converter == null && beanFactory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory cFB = (ConfigurableBeanFactory) beanFactory;
ConversionService conversionService = cFB.getConversionService();
converter = (conversionService != null ? new Converter(conversionService)
: new Converter(cFB.getTypeConverter()));
}
}
3.5.JdkSerializationRedisSerializer
- 針對object數據類型;
- 序列化時直接使用java的ByteArrayOutputStream把對象轉換爲byte;
- 反序列化時直接使用java把ByteArrayInputStream把byte轉換爲對象;
- 序列化把對象轉換爲對象的java字節碼,可閱讀性比較差;
- JdkSerializationRedisSerializer
//**序列化轉換器
private final Converter<Object, byte[]> serializer;
//**反序列化轉換器
private final Converter<byte[], Object> deserializer;
//**使用SerializingConverter和DeserializingConverter做爲默認的序列化和反序列化轉換器
public JdkSerializationRedisSerializer() {
this(new SerializingConverter(), new DeserializingConverter());
}
public Object deserialize(@Nullable byte[] bytes) {
...
//**調用反序列化轉換器把byte轉換爲object對象
return deserializer.convert(bytes);
...
}
@Override
public byte[] serialize(@Nullable Object object) {
...
//**調用序列化轉換器把byte轉換爲object對象
return serializer.convert(object);
...
}
- 序列化
- SerializingConverter.java
//**使用DefaultSerializer做爲默認的序列化器
public SerializingConverter() {
this.serializer = new DefaultSerializer();
}
@Override
public byte[] convert(Object source) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
...
//**調用DefaultSerializer的serialize方法序列化
this.serializer.serialize(source, byteStream);
return byteStream.toByteArray();
}
@Override
public void serialize(Object object, OutputStream outputStream) throws IOException {
//**必須實現Serializable接口
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
//**調用ObjectOutputStream的writeObject方法
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
}
- 反序列化同序列化基本一樣
3.6.GenericJackson2JsonRedisSerializer/Jackson2JsonRedisSerializer
- 針對object數據類型;
- 序列化時使用jackson的ObjectMapper把對象轉換爲json文本,然後轉換爲byte;
- 反序列化時使用jackson的ObjectMapper把byte轉換爲json文本,然後把json文本轉換爲對象;
- 序列化把對象轉換爲json文本,可閱讀性強;
- 區別
- Jackson2JsonRedisSerializer需要使用泛型;
- Jackson2JsonRedisSerializer可由調用者自定義ObjectMapper對象;也可使用內置ObjectMapper對象,但沒有任務配置;
- GenericJackson2JsonRedisSerializer可由調用者自定義ObjectMapper對象;也可使用內置ObjectMapper對象,它初始化了一些配置:
- 給null值註冊了一個類型序列化器;
- 會將除(String、Double、Integer、Double)外的非常量(non-final)的java類型信息的寫入到json文本中;
- Jackson2JsonRedisSerializer
//**需要指定泛型類型,反序列時轉換爲javaType後,在強轉爲指定的泛型類型
public class Jackson2JsonRedisSerializer<T> implements RedisSerializer<T> {
//**默認使用UTF_8字符集
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
//**java類型映射的jackson類型,反序列化時把json文本轉換爲javaType的類型
private final JavaType javaType;
//**默認的objectMapper
private ObjectMapper objectMapper = new ObjectMapper();
//**需指定反序列化時轉換爲的類型
public Jackson2JsonRedisSerializer(Class<T> type) {
this.javaType = getJavaType(type);
}
public Jackson2JsonRedisSerializer(JavaType javaType) {
this.javaType = javaType;
}
//**反序列化
public T deserialize(@Nullable byte[] bytes) throws SerializationException {
//**空值返回null
if (SerializationUtils.isEmpty(bytes)) {
return null;
}
...使用objectMapper把bytes轉換爲javaType的類型
return (T) this.objectMapper.readValue(bytes, 0, bytes.length, javaType);
...
}
//**序列化
public byte[] serialize(@Nullable Object t) throws SerializationException {
//**null返回空byte數組
if (t == null) {
return SerializationUtils.EMPTY_ARRAY;
}
...使用objectMapper把對象轉換爲byte數組
return this.objectMapper.writeValueAsBytes(t);
...
}
//**獲取java類型映射的jackson類型
protected JavaType getJavaType(Class<?> clazz) {
return TypeFactory.defaultInstance().constructType(clazz);
}
}
- GenericJackson2JsonRedisSerializer
public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Object> {
//**默認爲@class
public GenericJackson2JsonRedisSerializer() {
this((String) null);
}
//**設置默認的ObjectMapper,並初始化
//**classPropertyTypeName:jackon會將java類型信息的寫入到json文本中,classPropertyTypeName指定java類型信息寫入的格式
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {
//**默認的ObjectMapper
this(new ObjectMapper());
//**給null值註冊了一個類型序列化器
registerNullValueSerializer(mapper, classPropertyTypeName);
if (StringUtils.hasText(classPropertyTypeName)) {
//**指定了classPropertyTypeName爲java類型信息寫入的格式
mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, classPropertyTypeName);
} else {
//**指定了PROPERTY爲java類型信息寫入的格式,默認爲@class
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
}
}
//**序列化
public byte[] serialize(@Nullable Object source) throws SerializationException {
//**null返回空byte數組
if (source == null) {
return SerializationUtils.EMPTY_ARRAY;
}
...使用objectMapper把對象轉換爲byte數組
return mapper.writeValueAsBytes(source);
...
}
//**反序列化,默認轉換爲object對象
@Override
public Object deserialize(@Nullable byte[] source) throws SerializationException {
return deserialize(source, Object.class);
}
//**反序列化
@Nullable
public <T> T deserialize(@Nullable byte[] source, Class<T> type) throws SerializationException {
//**空值返回null
if (SerializationUtils.isEmpty(source)) {
return null;
}
...使用objectMapper把bytes轉換爲type類型
return mapper.readValue(source, type);
...
}
//**空值類型序列化器
private static class NullValueSerializer extends StdSerializer<NullValue> {
private static final long serialVersionUID = 1999052150548658808L;
private final String classIdentifier;
//**指定java類型信息寫入格式,默認爲@class
NullValueSerializer(@Nullable String classIdentifier) {
super(NullValue.class);
this.classIdentifier = StringUtils.hasText(classIdentifier) ? classIdentifier : "@class";
}
//**序列化
public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throwsIOException {
jgen.writeStartObject();
//**寫入空值的類型信息(@class, NullValue)
jgen.writeStringField(classIdentifier, NullValue.class.getName());
jgen.writeEndObject();
}
}
}
3.7.GenericFastJsonRedisSerializer/FastJsonRedisSerializer
- 針對object數據類型,是fastjson.jar裏面實現的RedisSerializer;
- 序列化時使用fastjson的JSON.toJSONBytes把對象轉換爲json文本,然後轉換爲byte;
- 反序列化時把byte轉換爲json文本,然後使用JSON.parseObject把json文本轉換爲對象;
- 序列化把對象轉換爲json文本,可閱讀性強;
- 區別
- FastJsonRedisSerializer需要使用泛型,序列化的反序列化泛型指定的類型;
- GenericFastJsonRedisSerializer序列化和反序列化object類型;
- FastJsonRedisSerializer
//**需要指定泛型類型,反序列時轉換爲type後,在強轉爲指定的泛型類型
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
//**序列化
public byte[] serialize(T t) throws SerializationException {
//**null返回空byte數組
if (t == null) {
return new byte[0];
}
...使用JSON.toJSONBytes把對象轉換爲byte數組
return JSON.toJSONBytes(t, fastJsonConfig.getSerializeConfig(), fastJsonConfig.getSerializerFeatures());
...
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
//**空值返回null
if (bytes == null || bytes.length == 0) {
return null;
}
...使用JSON.parseObject把bytes轉換爲type類型
return (T) JSON.parseObject(bytes, type, fastJsonConfig.getFeatures());
...
}
}
- GenericFastJsonRedisSerializer
public class GenericFastJsonRedisSerializer implements RedisSerializer<Object> {
//**序列化
public byte[] serialize(Object object) throws SerializationException {
//**null返回空byte數組
if (object == null) {
return new byte[0];
}
...使用JSON.toJSONBytes把對象轉換爲byte數組
return JSON.toJSONBytes(object, SerializerFeature.WriteClassName);
...
}
//**反序列化
public Object deserialize(byte[] bytes) throws SerializationException {
//**空值返回null
if (bytes == null || bytes.length == 0) {
return null;
}
...先把bytes轉換爲string,然後使用JSON.parseObject把string轉換爲obejct類型
return JSON.parseObject(new String(bytes, IOUtils.UTF8), Object.class, defaultRedisConfig);
...
}
}
3.8.OxmSerializer
- 針對object數據類型;
- 序列化時使用spring oxm的Marshaller把對象轉換爲xml文本,然後轉換爲byte;
- 反序列化時使用spring oxm的Unmarshaller把byte轉換爲xml文本,然後把xml文本轉換爲對象;
- 序列化把對象轉換爲xml文本,可閱讀性強;
//**實現了InitializingBean接口,spring容器啓用時,會調用afterPropertiesSet方法進行一些初始化,同類型還有 @PostConstruct
public class OxmSerializer implements InitializingBean, RedisSerializer<Object> {
//**初始化,驗證marshaller/unmarshaller不能爲空,marshaller/unmarshaller必須傳入,沒有默認值
@Override
public void afterPropertiesSet() {
Assert.state(marshaller != null, "non-null marshaller required");
Assert.state(unmarshaller != null, "non-null unmarshaller required");
}
//**反序列化
public Object deserialize(@Nullable byte[] bytes) throws SerializationException {
//**空值返回null
if (SerializationUtils.isEmpty(bytes)) {
return null;
}
...使用unmarshaller把bytes轉換爲type類型
return unmarshaller.unmarshal(new StreamSource(new ByteArrayInputStream(bytes)));
...
}
//**序列化
public byte[] serialize(@Nullable Object t) throws SerializationException {
//**null返回空byte數組
if (t == null) {
return SerializationUtils.EMPTY_ARRAY;
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
StreamResult result = new StreamResult(stream);
...使用marshaller把對象轉換爲xml文本,然後寫入ByteArrayOutputStream
marshaller.marshal(t, result);
...
//**把ByteArrayOutputStream轉換爲byte數組
return stream.toByteArray();
}
}