文章

spring-data-redis中的Jackson2JsonRedisSerializer研读

  spring-data-redis是springboot的一个对redis的封装包。它是springFramework的一个默认的redis驱动jar包。spring已经在这个jar包里面封装了redis各种功能。其中的redisSerializer接口就是用来序列化存入redis数据格式的一种策略。spring官根据不同种情况已经为我们内置了很多序列化器,我们可以通过查看有哪些类实现了redisSerializer接口就可以得知。下面我就总结一下我对其中一种策略-jackson2Json的序列策略的研读。

  首先,Jackson2JsonRedisSerializer一共有6个方法。

方法 解释
Jackson2JsonRedisSerializer(Class clazz) 构造方法
Jackson2JsonRedisSerializer(JavaType javaType) 构造方法
deserialize 实现
serialize 实现
setObjectMapper 独有
getJavaType 独有
  • Jackson2JsonRedisSerializer(Class clazz)
1
2
3
4
5
6
7
8
/**
	 * Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link Class}.
	 *
	 * @param type
	 */
	public Jackson2JsonRedisSerializer(Class<T> type) {
		this.javaType = getJavaType(type);
	}

  根据传入的参数类型,通过getJavaType方法指定为databind的类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
	 * 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相对应的具体类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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中的方法。

1
2
3
4
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的封装中的一个策略,这个策略满足了要保存的数据有比较复杂的层级结构,而且效率还是非常高的。建议用这个策略进行保存,只是可读性差了一些。

本文由作者按照 CC BY 4.0 进行授权