概括
一般redis的序列化方式主要有:字符串序列化、json序列化、xml序列化、jdk序列化,具体可查阅org.springframework.data.redis.serializer.RedisSerializer 的实现类,其中对于json序列化,官方实现的是jackson的序列化,此外fastjson也有对应的实现。
源码分析
下面开始对spring-data-redis的源码稍加分析。
key、hash key的序列化一般使用如下方式:
...
/**
* Simple String to byte[] (and back) serializer. Converts Strings into bytes and vice-versa using the specified charset
* (by default UTF-8).
* <p>
* Useful when the interaction with the Redis happens mainly through Strings.
* <p>
* Does not perform any null conversion since empty strings are valid keys/values.
*
* @author Costin Leau
* @author Christoph Strobl
*/
public class StringRedisSerializer implements RedisSerializer<String> {
private final Charset charset;
public StringRedisSerializer() {
this(Charset.forName("UTF8"));
}
public StringRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
public byte[] serialize(String string) {
return (string == null ? null : string.getBytes(charset));
}
}
可以看出使用的是字符串的序列化很常规
value、hash value的序列化一般使用如下方式:
part I
...
/**
* Java Serialization Redis serializer. Delegates to the default (Java based) {@link DefaultSerializer serializer} and
* {@link DefaultDeserializer}. This {@link RedisSerializer serializer} can be constructed with either custom
* {@link ClassLoader} or own {@link Converter converters}.
*/
public class JdkSerializationRedisSerializer implements RedisSerializer<Object> {
// 三个构造函数
// 默认构造函数
public JdkSerializationRedisSerializer(){
this(new SerializingConverter(), new DeserializingConverter());}
// 指定ClassLoader的构造函数(热部署时可能需要用到,避免不同的类加载器搞混)
public JdkSerializationRedisSerializer(ClassLoader classLoader){...}
// 指定org.springframework.core.convert.converter.Converter的构造函数(严重依赖spring框架,也可以自己实现)
public JdkSerializationRedisSerializer(Converter<Object, byte[]> serializer, Converter<byte[], Object> deserializer){...};
...
part II
...
org.springframework.core.serializer.support.SerializingConverter#convert
/**
* Serializes the source object and returns the byte array result.
*/
@Override
public byte[] convert(Object source) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
try {
this.serializer.serialize(source, byteStream);// 根据构造函数可知这里使用默认的序列化器
return byteStream.toByteArray();
}
catch (Throwable ex) {
throw new SerializationFailedException("Failed to serialize object using " +
this.serializer.getClass().getSimpleName(), ex);
}
}
...
part III
...
org.springframework.core.serializer.DefaultSerializer#serialize
/**
* 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();
}
...
以上可以知道常规的序列化方式;
接下来看反序列化方式:
part IV
...
org.springframework.core.serializer.support.DeserializingConverter#convert
public Object convert(byte[] source) {
ByteArrayInputStream byteStream = new ByteArrayInputStream(source);
try {
return this.deserializer.deserialize(byteStream);// 根据构造函数可知这里使用默认的反序列化器
}
catch (Throwable ex) {
throw new SerializationFailedException("Failed to deserialize payload. " +
"Is the byte array a result of corresponding serialization for " +
this.deserializer.getClass().getSimpleName() + "?", ex);
}
}
...
part V
...
org.springframework.core.serializer.DefaultDeserializer#deserialize
/**
* Read from the supplied {@code InputStream} and deserialize the contents
* into an object.
* @see ObjectInputStream#readObject()
*/
@Override
@SuppressWarnings("resource")
public Object deserialize(InputStream inputStream) throws IOException {
ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
try {
return objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
}
...
part VI
...
/**
* Special ObjectInputStream subclass that resolves class names
* against a specific ClassLoader. Serves as base class for
* {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream}.
*
* @author Juergen Hoeller
* @since 2.5.5
*/
public class ConfigurableObjectInputStream extends ObjectInputStream {
...
@Override
protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
try {
if (this.classLoader != null) {
// Use the specified ClassLoader to resolve local classes.
return ClassUtils.forName(classDesc.getName(), this.classLoader);
}
else {
// Use the default ClassLoader...
return super.resolveClass(classDesc);
}
}
catch (ClassNotFoundException ex) {
return resolveFallbackIfPossible(classDesc.getName(), ex);
}
}
@Override
protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {
if (!this.acceptProxyClasses) {
throw new NotSerializableException("Not allowed to accept serialized proxy classes");
}
if (this.classLoader != null) {
// Use the specified ClassLoader to resolve local proxy classes.
Class<?>[] resolvedInterfaces = new Class<?>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
try {
resolvedInterfaces[i] = ClassUtils.forName(interfaces[i], this.classLoader);
}
catch (ClassNotFoundException ex) {
resolvedInterfaces[i] = resolveFallbackIfPossible(interfaces[i], ex);
}
}
try {
return ClassUtils.createCompositeInterface(resolvedInterfaces, this.classLoader);
}
catch (IllegalArgumentException ex) {
throw new ClassNotFoundException(null, ex);
}
}
else {
// Use ObjectInputStream's default ClassLoader...
try {
return super.resolveProxyClass(interfaces);
}
catch (ClassNotFoundException ex) {
Class<?>[] resolvedInterfaces = new Class<?>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
resolvedInterfaces[i] = resolveFallbackIfPossible(interfaces[i], ex);
}
return ClassUtils.createCompositeInterface(resolvedInterfaces, getFallbackClassLoader());
}
}
}
...
以上可以看出反序列化针对自定义传入Classloader的情况作了特殊处理
自定义序列化
通过分析源码后,如果不依赖于spring框架,我们可以自定义比较常规的序列化的方式:
字符串序列化:
package com.caiya.test.serialization.jdk;
import com.caiya.test.serialization.Serializer;
import com.caiya.test.serialization.exception.SerializationException;
import java.nio.charset.Charset;
/**
* Simple String to byte[] (and back) serializer. Converts Strings into bytes and vice-versa using the specified charset
* (by default UTF-8).
* <p/>
* Useful when the interaction with the Redis happens mainly through Strings.
* <p/>
* Does not perform any null conversion since empty strings are valid keys/values.
*
* @author wangnan
* @since 1.0
*/
public class StringSerializer implements Serializer<String> {
private final Charset charset;
public StringSerializer() {
this(Charset.forName("UTF-8"));
}
public StringSerializer(Charset charset) {
if (charset == null)
throw new IllegalArgumentException("Charset must not be null!");
this.charset = charset;
}
@Override
public byte[] serialize(String string) throws SerializationException {
return (string == null ? null : string.getBytes(charset));
}
@Override
public String deserialize(byte[] bytes) throws SerializationException {
return (bytes == null ? null : new String(bytes, charset));
}
}
jdk序列化:
package com.caiya.test.serialization.jdk;
import com.caiya.test.serialization.Serializer;
import com.caiya.test.serialization.exception.NestedIOException;
import com.caiya.test.serialization.exception.SerializationException;
import com.caiya.test.serialization.exception.SerializationFailedException;
import java.io.*;
/**
* Java Serialization serializer.
*
* @author wangnan
* @since 1.0
*/
public class JdkSerializationSerializer implements Serializer<Object> {
private final ClassLoader classLoader;
public JdkSerializationSerializer() {
this.classLoader = null;
}
public JdkSerializationSerializer(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public byte[] serialize(Object object) throws SerializationException {
if (object == null) {
return SerializationUtils.EMPTY_ARRAY;
}
try {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
return byteStream.toByteArray();
} catch (Exception ex) {
throw new SerializationException("Cannot serialize", ex);
}
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
if (SerializationUtils.isEmpty(bytes)) {
return null;
}
try {
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
try {
ObjectInputStream objectInputStream = new ObjectInputStream(byteStream);
// 如果需要自定义ClassLoader,需要额外实现。 ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(byteStream, this.classLoader);
try {
return objectInputStream.readObject();
} catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
} catch (Throwable ex) {
throw new SerializationFailedException("Failed to deserialize payload. " +
"Is the byte array a result of corresponding serialization for " +
this.getClass().getSimpleName() + "?", ex);
}
} catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
}
}