FastJSON 源码分析

作者: 被称为L的男人 | 来源:发表于2017-08-10 15:22 被阅读357次

    Git 链接

    Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。

    git:https://github.com/alibaba/fastjson

    Samples:https://github.com/alibaba/fastjson/wiki/Samples-DataBind

    测试代码

    @Test
    public void test() {
        User user = new User(0L, "json");
        String jsonString = JSON.toJSONString(user);
        System.out.println(jsonString);
        User parseUser = JSON.parseObject(jsonString, User.class);
        System.out.println(parseUser);
    }
    
    public class User {
        private Long   id;
        private String name;
        
        public User(long id, String name) {
            this.id = id;
            this.name = name;
        }
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        
        @Override
        public String toString() {
            return "User [id=" + id + ", name=" + name + "]";
        }
    }
    

    输出:

    {"id":0,"name":"json"}
    User [id=0, name=json]
    

    序列化、反序列化流程

    序列化流程

    根据对象的实例,获取对象的类,判断出实现 ObjectSerializer 接口的类,调用接口的方法 write,将对象实例转化成 String。

    反序列化流程

    根据输入的 Class<T> clazz,判断出实现 ObjectDeserializer 的类,调用接口的方法 deserialze,将 String 转化成对象实例。

    序列化源码分析

    最终会调用到函数:

    public static String toJSONString(Object object, // 
                                      SerializeConfig config, // 
                                      SerializeFilter[] filters, // 
                                      String dateFormat, //
                                      int defaultFeatures, // 
                                      SerializerFeature... features) {
        // out 对象保存解析对象的结果,最终会转换成 string(return out.toString();)
        SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
        try {
            // 解析对象的类
            JSONSerializer serializer = new JSONSerializer(out, config);
            
            if (dateFormat != null && dateFormat.length() != 0) {
                serializer.setDateFormat(dateFormat);
                serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
            }
            if (filters != null) {
                for (SerializeFilter filter : filters) {
                    serializer.addFilter(filter);
                }
            }
            // 将对象 object 解析成 string,保存在内部的 out 中
            serializer.write(object);
            return out.toString();
        } finally {
            out.close();
        }
    }
    

    其中 write 方法如下:

    public final void write(Object object) {
        if (object == null) {
            out.writeNull();
            return;
        }
        Class<?> clazz = object.getClass();
        /**
         * 获取到对应的解析类,所有的类都实现了接口 ObjectSerializer
         * 
         * 如果是 bool,会定位到 BooleanCodec 类
         * 如果是 bool[],会定位到 PrimitiveArraySerializer 类
         */
        ObjectSerializer writer = getObjectWriter(clazz);
        try {
            // 调用 write 方法,把对应的域,写入 out 对象中!
            writer.write(this, object, null, null, 0);
        } catch (IOException e) {
            throw new JSONException(e.getMessage(), e);
        }
    }
    

    在测试用例中,使用的是类 JavaBeanSerializer,因为要序列化的是自定义的 JavaBean 类 User。

    SerializeConfig

    其中 put 函数是将键值对放入 IdentityHashMap<Type, ObjectSerializer> serializers 中。

    public SerializeConfig(int tableSize, boolean fieldBase) {
        this.fieldBased = fieldBase;
        serializers = new IdentityHashMap<Type, ObjectSerializer>(tableSize);
        
        try {
            if (asm) {
                asmFactory = new ASMSerializerFactory();
            }
        } catch (Throwable eror) {
            asm = false;
        }
        put(Boolean.class, BooleanCodec.instance);
        put(Character.class, CharacterCodec.instance);
        put(Byte.class, IntegerCodec.instance);
        put(Short.class, IntegerCodec.instance);
        put(Integer.class, IntegerCodec.instance);
        put(Long.class, LongCodec.instance);
        put(Float.class, FloatCodec.instance);
        put(Double.class, DoubleSerializer.instance);
        put(BigDecimal.class, BigDecimalCodec.instance);
        put(BigInteger.class, BigIntegerCodec.instance);
        put(String.class, StringCodec.instance);
        put(byte[].class, PrimitiveArraySerializer.instance);
        put(short[].class, PrimitiveArraySerializer.instance);
        put(int[].class, PrimitiveArraySerializer.instance);
        put(long[].class, PrimitiveArraySerializer.instance);
        put(float[].class, PrimitiveArraySerializer.instance);
        put(double[].class, PrimitiveArraySerializer.instance);
        put(boolean[].class, PrimitiveArraySerializer.instance);
        put(char[].class, PrimitiveArraySerializer.instance);
        put(Object[].class, ObjectArrayCodec.instance);
        put(Class.class, MiscCodec.instance);
        // 省略……
        put(LinkedList.class, CollectionCodec.instance);
    }
    

    分析其中的代码:

    put(Boolean.class, BooleanCodec.instance);
    

    类 BooleanCodec 继承了接口 ObjectSerializer, ObjectDeserializer,两个接口:

    public interface ObjectSerializer {
        
        /**
         * fastjson invokes this call-back method during serialization when it encounters a field of the
         * specified type.
         * @param serializer 
         * @param object src the object that needs to be converted to Json.
         * @param fieldName parent object field name
         * @param fieldType parent object field type
         * @param features parent object field serializer features
         * @throws IOException
         */
        void write(JSONSerializer serializer, //
                   Object object, //
                   Object fieldName, //
                   Type fieldType, //
                   int features) throws IOException;
    }
    
    public interface ObjectDeserializer {
        /**
         * fastjson invokes this call-back method during deserialization when it encounters a field of the
         * specified type.
         * <p>In the implementation of this call-back method, you should consider invoking
         * {@link JSON#parseObject(String, Type, Feature[])} method to create objects
         * for any non-trivial field of the returned object. 
         *
         * @param parser context DefaultJSONParser being deserialized
         * @param type The type of the Object to deserialize to
         * @param fieldName parent object field name
         * @return a deserialized object of the specified type which is a subclass of {@code T}
         */
        <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
        
        int getFastMatchToken();
    }
    

    BooleanCodec 的 write 实现如下,其中参数 serializer 中包含实例为 out 的 SerializeWriter 对象,out 最终转换成输出的 string;

    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
        SerializeWriter out = serializer.out;
        Boolean value = (Boolean) object;
        if (value == null) {
            out.writeNull(SerializerFeature.WriteNullBooleanAsFalse);
            return;
        }
        if (value.booleanValue()) {
            out.write("true");
        } else {
            out.write("false");
        }
    }
    

    BooleanCodec 的 deserialze 实现如下,如果 lexer.token() 是 true、1等,就会返回true;类 JSONToken 中有对各种字符的定义。

    @SuppressWarnings("unchecked")
    public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
        final JSONLexer lexer = parser.lexer;
        Boolean boolObj;
        try {
            if (lexer.token() == JSONToken.TRUE) {
                lexer.nextToken(JSONToken.COMMA);
                boolObj = Boolean.TRUE;
            } else if (lexer.token() == JSONToken.FALSE) {
                lexer.nextToken(JSONToken.COMMA);
                boolObj = Boolean.FALSE;
            } else if (lexer.token() == JSONToken.LITERAL_INT) {
                int intValue = lexer.intValue();
                lexer.nextToken(JSONToken.COMMA);
                if (intValue == 1) {
                    boolObj = Boolean.TRUE;
                } else {
                    boolObj = Boolean.FALSE;
                }
            } else {
                Object value = parser.parse();
                if (value == null) {
                    return null;
                }
                boolObj = TypeUtils.castToBoolean(value);
            }
        } catch (Exception ex) {
            throw new JSONException("parseBoolean error, field : " + fieldName, ex);
        }
        if (clazz == AtomicBoolean.class) {
            return (T) new AtomicBoolean(boolObj.booleanValue());
        }
        return (T) boolObj;
    }
    

    反序列化

    在反序列化string到对象时,会调用下面的函数。其中最重要的是第25行代码,将输入的input字符串转换成对应的class类型。

    @SuppressWarnings("unchecked")
    public static <T> T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor,
                                          int featureValues, Feature... features) {
        if (input == null) {
            return null;
        }
        if (features != null) {
            for (Feature feature : features) {
                featureValues |= feature.mask;
            }
        }
        DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues);
        if (processor != null) {
            if (processor instanceof ExtraTypeProvider) {
                parser.getExtraTypeProviders().add((ExtraTypeProvider) processor);
            }
            if (processor instanceof ExtraProcessor) {
                parser.getExtraProcessors().add((ExtraProcessor) processor);
            }
            if (processor instanceof FieldTypeResolver) {
                parser.setFieldTypeResolver((FieldTypeResolver) processor);
            }
        }
        // 获取所需要的类
        T value = (T) parser.parseObject(clazz, null);
        parser.handleResovleTask(value);
        parser.close();
        return (T) value;
    }
    

    T value = (T) parser.parseObject(clazz, null) 的代码如下,对于本例中的 User 对象,最终ObjectDeserializer会定位到类JavaBeanDeserializer,其 deserialze 代码有点长,就不贴出来了。

    @SuppressWarnings("unchecked")
    public <T> T parseObject(Type type, Object fieldName) {
        int token = lexer.token();
        if (token == JSONToken.NULL) {
            lexer.nextToken();
            return null;
        }
        if (token == JSONToken.LITERAL_STRING) {
            if (type == byte[].class) {
                byte[] bytes = lexer.bytesValue();
                lexer.nextToken();
                return (T) bytes;
            }
            if (type == char[].class) {
                String strVal = lexer.stringVal();
                lexer.nextToken();
                return (T) strVal.toCharArray();
            }
        }
        // 根据输入的class类型,获取解析所需要的类
        ObjectDeserializer derializer = config.getDeserializer(type);
        try {
            return (T) derializer.deserialze(this, type, fieldName);
        } catch (JSONException e) {
            throw e;
        } catch (Throwable e) {
            throw new JSONException(e.getMessage(), e);
        }
    }
    

    其它用法

    可以利用fastjson,将"1 2 3 4 5" 或 "1,2,3,4,5"这样的字符串,转换成数组。实际应用过程中,十分方便简洁。

    @Test
    public void testArray() {
        String arrayString = "1 2 3 4 5";
        int[] array1 = JSON.parseObject("[" + arrayString + "]", int[].class);
        System.out.println(Arrays.toString(array1));
        
        String boolString = "1, true, 0, false";
        boolean[] array2 = JSON.parseObject("[" + boolString + "]", boolean[].class);
        System.out.println(Arrays.toString(array2));
    }
    

    fastjson 的整理思路

    总的来说,是定义了两个接口:ObjectSerializer 和 ObjectDeserializer 。针对不同的类,实现了不同的序列化和反序列化方式,并能够根据类的信息,选择合适的接口实现类。

    总结

    仅仅通过序列化、反序列化一个Java Bean对象,对fastjson的源码进行分析。很多地方没有展开讨论,至少没法通过博客的形式写出来,具体细节太多了。如果有什么问题,欢迎指正~

    相关文章

      网友评论

        本文标题:FastJSON 源码分析

        本文链接:https://www.haomeiwen.com/subject/xpphrxtx.html