spring-data-redis是springboot的一个对redis的封装包。它是springFramework的一个默认的redis驱动jar包。spring已经在这个jar包里面封装了redis各种功能。其中的redisSerializer接口就是用来序列化存入redis数据格式的一种策略。spring官根据不同种情况已经为我们内置了很多序列化器,我们可以通过查看有哪些类实现了redisSerializer接口就可以得知。下面我就总结一下我对其中一种策略-jackson2Json的序列策略的研读。
首先,Jackson2JsonRedisSerializer一共有6个方法。
方法 | 解释 |
---|---|
Jackson2JsonRedisSerializer(Class |
构造方法 |
Jackson2JsonRedisSerializer(JavaType javaType) | 构造方法 |
deserialize | 实现 |
serialize | 实现 |
setObjectMapper | 独有 |
getJavaType | 独有 |
- Jackson2JsonRedisSerializer(Class
clazz)
/**
* Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link Class}.
*
* @param type
*/
public Jackson2JsonRedisSerializer(Class<T> type) {
this.javaType = getJavaType(type);
}
根据传入的参数类型,通过getJavaType方法指定为databind的类型。
/**
* Returns the Jackson {@link JavaType} for the specific class.
* <p>
* Default implementation returns {@link TypeFactory#constructType(java.lang.reflect.Type)}, but this can be
* overridden in subclasses, to allow for custom generic collection handling. For instance:
*
* <pre class="code">
* protected JavaType getJavaType(Class<?> clazz) {
* if (List.class.isAssignableFrom(clazz)) {
* return TypeFactory.defaultInstance().constructCollectionType(ArrayList.class, MyBean.class);
* } else {
* return super.getJavaType(clazz);
* }
* }
* </pre>
*
* @param clazz the class to return the java type for
* @return the java type
*/
protected JavaType getJavaType(Class<?> clazz) {
return TypeFactory.defaultInstance().constructType(clazz);
}
JavaType类属于com.fasterxml.jackson.databind包。它是一种令牌类的基类,用于保存信息和反序列化器的key。通过getJavaType方法经过反射来构造出指定的class。我们看到其中应用到了TypeFactory,用TypeFactory的作用就是快速的获取到clazz相对应的具体类型。
public final class TypeFactory implements java.io.Serializable
{
//将clazz传入,通过_formAny方法构造。Class<?> 是实现了Type接口
public JavaType constructType(Type type) {
return _fromAny(null, type, EMPTY_BINDINGS);
}
....
/**
* Factory method that can be used if type information is passed
* as Java typing returned from <code>getGenericXxx</code> methods
* (usually for a return or argument type).
*/
protected JavaType _fromAny(ClassStack context, Type type, TypeBindings bindings)
{
JavaType resultType;
// simple class?
if (type instanceof Class<?>) {
// Important: remove possible bindings since this is type-erased thingy
//判断type是一个简单class。然后调用_formClass
//ClassStack是一个工具类,用来记录调用栈信息的上下文。
//EMPTY_BINDINGS是TypeBindings中的常量。TypeBindings是用于解析给定类的类型参数的助手类。也就是说这个常量为空绑定关系。
resultType = _fromClass(context, (Class<?>) type, EMPTY_BINDINGS);
}
// But if not, need to start resolving.
else if (type instanceof ParameterizedType) {...}
...
}
/**
* @param bindings Mapping of formal parameter declarations (for generic
* types) into actual types
*/
protected JavaType _fromClass(ClassStack context, Class<?> rawType, TypeBindings bindings)
{
// Very first thing: small set of core types we know well:
//第一件事就是通过rawType来判断是哪种众所周知的简单类型。首先判断是否是原始类型,并且是否是BOOL,INT,LONG。如果不是就是String,Object。否则返回null
JavaType result = _findWellKnownSimple(rawType);
if (result != null) {
return result;
}
// Barring that, we may have recently constructed an instance
final Object key;
if ((bindings == null) || bindings.isEmpty()) {
//key是这种Bool Int Long String object中的一种
key = rawType;
} else {
key = bindings.asKey(rawType);
}
//_typeCache是一个LRUMap。LRUMap其实底层是个ConcurrentHashMap。它用来帮助我们避免核心类型的重复解析。尤其为了泛型的解析。
result = _typeCache.get(key); // ok, cache object is synced
if (result != null) {
return result;
}
//一般到这里就结束了。但是,如果通过我们传入的rawType没有找到绑定的关系,那就有可能是个复杂结构的结构体(递归引用)。接下来就需要通过调用栈来追踪整个结构了。
// 15-Oct-2015, tatu: recursive reference?
if (context == null) {
context = new ClassStack(rawType);
} else {
ClassStack prev = context.find(rawType);
if (prev != null) {
// Self-reference: needs special handling, then...
//可以看到,resolvedRecursiveType这个方法是用来自我引用的一个内部类型。他继承自TypeBase,TypeBase继承自javaType。
ResolvedRecursiveType selfRef = new ResolvedRecursiveType(rawType, EMPTY_BINDINGS);
prev.addSelfReference(selfRef);
return selfRef;
}
// no, but need to update context to allow for proper cycle resolution
context = context.child(rawType);
}
//到这里,可以将递归引用的结构解析到context变量里了。
// First: do we have an array type?
if (rawType.isArray()) {
result = ArrayType.construct(_fromAny(context, rawType.getComponentType(), bindings),
bindings);
} else {
// If not, need to proceed by first resolving parent type hierarchy
//首先解析父类型层次结构
JavaType superClass;
JavaType[] superInterfaces;
if (rawType.isInterface()) {
superClass = null;
//返回的是一个JavaType的数组。
//如果是个超接口(superInterface),通过反射返回的必须是实际用过的类型(interface or class)。
//如果是个class,返回的是个数组,数组中包含着所有实现过的接口。
//如果是个interface,返回的是个数组,数组中包含所有直接继承过的接口。
//如果是个class或者interface,就返回个一个长度为0的数组。
//如果是基础类型或者void,就返回一个长度为0的数组。
superInterfaces = _resolveSuperInterfaces(context, rawType, bindings);
} else {
// Note: even Enums can implement interfaces, so cannot drop those
//返回class表示的实体(类、接口、基本类型型或void)的直接超类
superClass = _resolveSuperClass(context, rawType, bindings);
superInterfaces = _resolveSuperInterfaces(context, rawType, bindings);
}
// 19-Oct-2015, tatu: Bit messy, but we need to 'fix' java.util.Properties here...
if (rawType == Properties.class) {
result = MapType.construct(rawType, bindings, superClass, superInterfaces,
CORE_TYPE_STRING, CORE_TYPE_STRING);
}
// And then check what flavor of type we got. Start by asking resolved
// super-type if refinement is all that is needed?
else if (superClass != null) {
result = superClass.refine(rawType, bindings, superClass, superInterfaces);
}
// if not, perhaps we are now resolving a well-known class or interface?
if (result == null) {
result = _fromWellKnownClass(context, rawType, bindings, superClass, superInterfaces);
if (result == null) {
result = _fromWellKnownInterface(context, rawType, bindings, superClass, superInterfaces);
if (result == null) {
// but if nothing else, "simple" class for now:
result = _newSimpleType(rawType, bindings, superClass, superInterfaces);
}
}
}
}
context.resolveSelfReferences(result);
// 16-Jul-2016, tatu: [databind#1302] is solved different way, but ideally we shouldn't
// cache anything with partially resolved `ResolvedRecursiveType`... so maybe improve
if (!result.hasHandlers()) {
_typeCache.putIfAbsent(key, result); // cache object syncs
}
return result;
}
}
- Jackson2JsonReisSerializer(JavaType javaType)
另一个构造方法,参数是JavaType类型。
- deserialize(@Nullable byte[] bytes)
反序列化方法,可为null的byte数组为参数。如果是空或者null的话,返回null。否则,通过ObjectMapper将byte数组进行反序列化。
ObjectMapper提供读和写JSON的能力。不论是转成POJO还是从POJO转出,或者是转成JSON还是从JSON转出,还是一些相关的转化功能。ObjectMapper都可以高定制化的兼容不同种的JSON格式。
- serialize(@Nullable Object t)
序列化方法,同上。t如果为null,则返回空byte数组。否则,将t序列化。
- setObjectMapper(ObjectMapper objectMapper)
这个方法比较有用,它可以用来自定义JSON序列化进程的。相关设置可以参见ObjectMapper.java中的方法。
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
- getJavaType(Class<?> clazz)
这个方法是被Jackson2JsonRedisSerializer方法调用的,用途就是返回指定class的jackson格式。
通过简单阅读了这个类的源码,我对这个类也有了大致的了解。作为spring-data-redis对redis的封装中的一个策略,这个策略满足了要保存的数据有比较复杂的层级结构,而且效率还是非常高的。建议用这个策略进行保存,只是可读性差了一些。