alibaba fastjson(json序列化器)序列化部分源碼解析-1-整體分析

fastjson官方地址: http://code.alibabatech.com/wiki/display/FastJSON/Home
    從javaeye上看到了阿里一位人士寫的fastjson,特別是其中如何將java對象序列化成json字符串這段。筆者比較關注,由於在筆者的項目中就用了一個json序列化器(造的輪子)。就下載下來看了一看,先不說和筆者所用的輪子有何區別,單就用了一個簡單的測試器,來測試一下二者的處理速度。測試代碼就不貼了,簡單地說下測試結果。在jvm充分優化的狀況下(for循環執行了不少次以後),筆者所使用的java序列化器處理速度不是很均勻,在結尾有短暫的變化(可能與虛擬機回收有關係);而fastjson在後面的處理過程中,通常很均勻(後來發現與使用的buf分配方式有關)。最主要的區別莫在於,fastjson的速度那是不能對比了。
    通過分析源碼以後,發現fastjson在處理json優化上面仍是下了很大的工夫的。筆者準備從如下幾個方面對fastjson做一個簡單的解析,也讓使用fastjson的同窗對fastjson有一個簡單的認識。
        1    整體分析    分析json序列化的整體思路和解析過程
        2    性能分析A  針對字符生產部分(即outWriter)對不一樣類型數據的處理和與性能相關處理部分
        3    性別分析B  針對序列化過程部分(即objectSerializer)對不一樣類型的序列化過程處理和與性能相關處理部分
        4    對象解析分析    對javaBean解析部分和針對字段輸出部分的處理和解析
    源碼分析基於1.0.5版本。javascript

    整體分析,首先上圖,即fastjson的整體處理思想,其實也是全部json序列化器須要考慮的問題。java

 

    在這裏,須要考慮的主要有兩個部分,一是臨時保存在序列化過程當中用於儲存數據的容器,二是處理對象序列化的序列化器。
    在fastjson中,保存數據的容器使用了wirter,字符輸出流,並且是自實現的一個字符輸出流。相對原來的writer,追加了不少須要輸出的信息的實現,好比輸出一個字符串,輸出一個字符,輸出一個long類型數據等。而處理對象序列化的序列化器,而使用了責任鏈模式和工廠模式,將不一樣類型的java對象分散到不一樣的序列化器當中。而每一個序列化器只處理與自身類型相對應的數據信息,這樣就避免了在處理時,各類狀況交織在一塊,邏輯混亂的問題。
    下面就源碼自己做一個分析,其中結合兩個部分進行分析。web

 

    代碼分析部分json

    首先,將一個對象序列化json字符串調用的是JSON對象的toJSONString方法,這裏調用的是無參數方法。(注:本文不分析採用vistor實現json序列化代碼的部分)。具體代碼以下所示:數組

第一行,新產生的一個數據保存器,儲存在序列化過程當中產生的數據;第二行,產生統一的json序列化器,其中使用了outWriter,此類即json序列化的統一處理器;第三行,調用序列化方法開始序列化對象,以產生json字符串信息;第四行,返回已經儲存的json信息。性能優化

 

Java代碼    收藏代碼
  1. SerializeWriter out = new SerializeWriter();  
  2.        JSONSerializer serializer = new JSONSerializer(out);  
  3.        serializer.write(object);  
  4.        return out.toString();  
 

 

    數據保存器(序列化輸出容器)
   
    SerializeWriter是一個用於儲存在序列化過程當中產生的數據信息,它與jdk中的StringBuiler有着相似的功能,即將不一樣的數據填充到此容器中。之因此不使用StringBuilder的緣由之一在於StringBuilder沒有提供一些特別爲性能優化的方法,而且StringBuilder在處理過程當中增長了多餘的操做(如新分配對象)。該容器的主要功能就是接收不一樣的數據,並將這些數據存儲到該內部的一個字符數組當中,同時記錄字符總數。
    既然充當了一個數據輸出的角色,那麼就能夠往其中輸入任何的數據,包括int,byte,short等基本類型和對應的包裝類型,也包括日期數據,以及常用的字符串數據等。對於在這些數據類型以外的其它類型,因爲json的特殊結構,全部的高級類型都可以轉化於這些基礎類型的組織體,因此不須要再針對高級類型做處理了(這些是序列化器應該考慮的問題)。app

    首先對SerializeWriter的方法(輸出和追加)做一個預覽:jvm

方法總共能夠分五個部分,第一個部分是針對writer基本功能一個擴展,即支持輸出int,字符,以及字符數組,追加字符數組(包括字符串)等;第二個部分提供了寫整形和長整形的基本方法;第三個部分是提供寫基本數據類型數組的支持;第四個部分是提供寫一個數字+一個字符的形式,好比數據+[,\],}]這種格式;第五個部分是提供寫數據串,主是是針對字符串追加雙引號或單引號(以支持標準json)。源碼分析

 

Java代碼    收藏代碼
  1. public void write(int c)  
  2. public void write(char c)  
  3. public void write(char c[], int off, int len)  
  4. public void write(String str, int off, int len)  
  5. public SerializeWriter append(CharSequence csq)  
  6. public SerializeWriter append(CharSequence csq, int start, int end)  
  7. public SerializeWriter append(char c)  
  8.    
  9. public void writeInt(int i)  
  10. public void writeLong(long i)  
  11.    
  12. public void writeBooleanArray(boolean[] array)  
  13. public void writeShortArray(short[] array)  
  14. public void writeByteArray(byte[] array)  
  15. public void writeIntArray(int[] array)  
  16. public void writeIntArray(Integer[] array)  
  17. public void writeLongArray(long[] array)  
  18.    
  19. public void writeIntAndChar(int i, char c)  
  20. public void writeLongAndChar(long i, char c)  
  21.    
  22. public void writeStringWithDoubleQuote(String text)  
  23. public void writeKeyWithDoubleQuote(String text)  
  24. public void writeStringWithSingleQuote(String text)  
  25. public void writeStringArray(String[] array)  
  26. public void writeKeyWithSingleQuote(String text)  
  27. public void writeKeyWithDoubleQuoteIfHashSpecial(String text)  
  28. public void writeKeyWithSingleQuoteIfHashSpecial(String text)  
 

 

    五個部分的方法,每一個部分都有其特殊的做用和意義,針對最經常使用的數字和字符串做了特別的對待。性能

    在實現上面,SerializeWriter使用了一個內部的字符數組做爲數據的儲存器,同時使用了一個計數器計算當前存儲的字符量。既然使用了字符數組,那麼確定有相關的操做,如字符擴容等。整個寫數據的過程,其實就是往這個字符數組追加數據的過程,須要考慮只是如何追加數據的問題,即上面所列出的這麼多些方法。在最終寫完數據以後,便可將這個字符數組轉爲咱們所須要的字符串了。

    對象序列化入口

    JsonSerializer,準備地講,這個類不該該叫這個名字,由於它與其它的對象序列化器相混淆了。這只是一個提供對象序列化的一個入口;同時,它持有全部具體負責對象序列化工做類的引用。將這些序列化器集中起來,須要用到哪一個對象序列化器時,就取出這個序列化器,並調用相應的序列化方法。
    既然是對象序列化入口,它就須要關注兩個事情。一是咱們究竟有哪些序列化器可使用,二是對於一個對象,應該使用哪個序列化器來進行工做。對於這兩個問題,JsonSerializer內部持有一個JSONSerializerMap的屬性,即表示應該序列化的對象類型和對應的序列化器的一個映射。咱們來看默認的構造方法,它使用了默認的全局對象類型和對象序列化器映射:

 

Java代碼    收藏代碼
  1. public JSONSerializer(SerializeWriter out){  
  2.         this(out, JSONSerializerMap.getGlobalInstance());  
  3.     }  
 

 

這時使用了全局的一個對象序列化器映射,加上後面在getObjectWriter中追加的對象序列化器映射。在整個jsonSerializer中,可使用的對象序列化器有如下這些:

 

 

 

Java代碼    收藏代碼
  1. put(Boolean.class, BooleanSerializer.instance);  
  2.         put(Byte.class, ByteSerializer.instance);  
  3.         put(Short.class, ShortSerializer.instance);  
  4.         put(Integer.class, IntegerSerializer.instance);  
  5.         put(Long.class, LongSerializer.instance);  
  6.         put(Float.class, FloatSerializer.instance);  
  7.         put(Double.class, DoubleSerializer.instance);  
  8.         put(BigDecimal.class, BigDecimalSerializer.instance);  
  9.         put(BigInteger.class, BigIntegerSerializer.instance);  
  10.         put(String.class, StringSerializer.instance);  
  11.         put(byte[].class, ByteArraySerializer.instance);  
  12.         put(short[].class, ShortArraySerializer.instance);  
  13.         put(int[].class, IntArraySerializer.instance);  
  14.         put(long[].class, LongArraySerializer.instance);  
  15.         put(float[].class, FloatArraySerializer.instance);  
  16.         put(double[].class, DoubleArraySerializer.instance);  
  17.         put(boolean[].class, BooleanArraySerializer.instance);  
  18.         put(Integer[].class, IntegerArraySerializer.instance);  
  19.         put(String[].class, StringArraySerializer.instance);  
  20.         put(Object[].class, ObjectArraySerializer.instance);  
  21.         put(Class.class, ClassSerializer.instance);  
  22.    
  23.         // atomic  
  24.         put(AtomicBoolean.class, AtomicBooleanSerializer.instance);  
  25.         put(AtomicInteger.class, AtomicIntegerSerializer.instance);  
  26.         put(AtomicLong.class, AtomicLongSerializer.instance);  
  27.         put(AtomicReference.class, AtomicReferenceSerializer.instance);  
  28.         put(AtomicIntegerArray.class, AtomicIntegerArraySerializer.instance);  
  29.         put(AtomicLongArray.class, AtomicLongArraySerializer.instance);  
  30.    
  31.         // jmx  
  32.         put(CompositeData.class, CompositeDataSerializer.instance);  
  33.         put(CompositeDataSupport.class, CompositeDataSerializer.instance);  
  34.         put(TabularData.class, TabularDataSerializer.instance);  
  35.         put(TabularDataSupport.class, TabularDataSerializer.instance);  
  36.         put(ObjectName.class, ObjectNameSerializer.instance);  
  37.         put(SimpleType.class, SimpleTypeSerializer.instance);  
  38.    
  39.         //在執行過程當中追加部分  
  40.                 mapping.put(clazz, MapSerializer.instance);  
  41.                 mapping.put(clazz, ListSerializer.instance);  
  42.                 mapping.put(clazz, CollectionSerializer.instance);  
  43.                 mapping.put(clazz, DateSerializer.instance);  
  44.                 mapping.put(clazz, JSONAwareSerializer.instance);  
  45.                 mapping.put(clazz, JSONStreamAwareSerializer.instance);  
  46.                 mapping.put(clazz, EnumSerializer.instance);  
  47.                 mapping.put(clazz, new ArraySerializer(compObjectSerializer));  
  48.                 mapping.put(clazz, new ExceptionSerializer(clazz));  
  49.                 mapping.put(clazz, new JavaBeanSerializer(clazz));  

 

     這些序列化器,覆蓋了基本數據,字符串類型,日期,以及集合,map,以及javaBean的全部序列化器。由於不存在沒有匹配不了的序列化器。既然有個序列化器,就能夠執行序列化工做了。即到了序列化入口應該作的工做了。

 

Java代碼    收藏代碼
  1. Class<?> clazz = object.getClass();  
  2.             ObjectSerializer writer = getObjectWriter(clazz);  
  3.             writer.write(this, object);  

     首先得到當前序列化對象所在的類型,再根據類型取得相對應的序列化器,最後使用序列化器進行正式的序列化工做。

 

 

    序列化過程

    正如上面所說,進入序列化工做以後,便是針對每一種類型進行序列化處理了。該序列化工做使用了統一的方法,即實現了統一的序列化方法:

Java代碼    收藏代碼
  1. void write(JSONSerializer serializer, Object object) throws IOException  

 

 

    該方法在抽象類(能夠說是接口)ObjectSerializer中定義,即全部的序列化器都繼承了此類,並實現了此方法用於處理不一樣的情形。對於上層調用(如JsonSerializer),不須要考慮每個類型的序列化工做是如何實現的,只須要針對不一樣的類型找到正確的序列化器,進行序列化工做便可。

    對於一個序列化器,一般的工做,是首先取得當前的數據儲存容器,而後根據不一樣的對象類型,將對象輸出到outWriter中便可。好比一個序列化實現IntergerSerializer,它的實現以下:

 

 


 

 

Java代碼    收藏代碼
  1. SerializeWriter out = serializer.getWrier();  
  2.         Integer value = (Integer) object;  
  3.         out.writeInt(value.intValue());  

 

    這 樣即完成了一個完整的序列化工做。固然,對於複雜的數據類型,在實現過程當中,可能須要遞歸地調用JsonSerializer的序列化工做,這得歸結於如何處理不一樣的對象類型了。好比處理一個對象集合時,除須要處理集合自己以外,還須要處理集合中的每個對象,這時又是一個解析過程。因爲使用了同一個jsonSerializer,因此在進行數據處理時,輸出的數據會按照在解析過程當中的順序,順序地寫入到outWriter中,這樣即保證了數據的正確性。

 

總結

    整個解析過程,相對來講,比較地簡單。由於,這個解析工做從原理上來說,也並不複雜。困難地在於,如何處理不一樣的數據類型,以及在處理過程當中如何保證處理的效率。這便是fastjson之因此產生的緣由。     本篇從整個結構出發,對fastjson中的json序列化過程有了一個初步的理解,讓你們都可以很好地正解fastjson,包括fastjson自己在實現上可能存在的不合理狀況。在下一篇中,就效率實現上的兩個重要方面(輸出效率和解析過程)分別進行解析。

相關文章
相關標籤/搜索