fastjson 過濾不需要序列化的屬性

JavaJSON技術框架選型與實例

 

JSON

JSON英文全稱爲JavaScriptObject Natation,採用key:value鍵值對的方式存貯數據,與xml格式相比,JSON是一種輕量級的數據交換格式;不要被Javascript這個單詞迷惑,實際上JSON只是一種數據格式,與具體語言並無關係。JSON已被廣泛應用於業界,比如目前NoSQL數據庫存貯大都採用key:value存貯結構,以Mongo爲例,其腳本語法甚至直接使用Javascript;在數據傳輸時,採用JSON格式也被廣泛應用,大部分開放API都開放JSON模式的數據輸出;在ajax請求數據時,json格式也被廣泛推薦。json更多信息的可以查看json官方網站http://json.org。

Java transient關鍵字

  JAVA規範原文The transient marker is not fully specified by the Java LanguageSpecification but is used in object serialization to mark member variables thatshould not be serialized.爲了方便存貯和網絡傳輸,java有系列化對象機制,transient可用來指定當前不想被系列化的成員對象。舉個例子說明transient的應用,在Mongo+Morphia開源項目下,如果對Java PO的成員指定transient,那麼該成員數據將不會被存入Mongo數據庫。另外一種應用場景就是這裏要講到的JSON,如果JAVA PO使用了Refrence(Mongo的Refrence)或者LazyLoading(可以理解成Hibernate LazyLoading概念),那麼大部分的開源JAVA JSON相關項目,會自動加載這些Refrence、LazyLoading對象,如果PO形成相互引用,那就會形成死循環,即使沒有形成死循環,大量不必要的數據被輸出到客戶端對資源的浪費也不容小覷。加上transient是一種解決辦法。

基於JAVA的JSON主要開源項目及其對比

Json開源項目非常多,如org.json、 JSON-Lib、jsontool、Jackson、Gson、SimpleJSON等等,後來專門查看了幾種json開源測試數據對比後,決定採用fastjson。展示兩組測試數據。首先來看大俠wangym(原博客http://wangym.iteye.com/blog/738933)對Jackson、JSON-Lib、Gson的測試結果

JSON轉Bean,5個線程併發,約200字節對象,1千萬次轉換:

Jackson

JSON-lib

Gson

吞吐量

64113.7

8067.4

13952.8

總耗時(秒)

155

1238

700

 Bean轉JSON,5個線程併發,約200字節對象,1千萬次轉換:

Jackson

JSON-lib

Gson

吞吐量

54802

15093.2

17308.2

總耗時(秒)

181

661

560

顯而易見,無論是哪種形式的轉換,Jackson > Gson > Json-lib

     Jackson的處理能力甚至高出Json-lib10倍左右

 

然後再拿溫少的fastjson與JSON-Lib、Simple-JSON、Jackson性能測試對比數據

性能對比

測試案例

JSON-Lib

Simple-JSON

Fastjson

Jackson

IntArray1000Decode

3,626

1,431

563

596

StringArray1000Decode

2,698

2,283

677

774

Map100StringDecode

515

597

208

230

功能對比

特性

JSON-Lib

Simple-JSON

Fastjson

Jackson

序列化支持數組

不支持

不支持

支持

支持

序列化支持Enum

不支持

不支持

支持

支持

支持JavaBean

不直接支持

不直接支持

支持

支持

 

可以看到Fastjson在性能方面,超越目前的所有java json proccesor,包括jackson

 

FastJson應用實例

1、利用Jquery ajax請求fastjson數據來顯示用戶列表例子實現

//定義一個User PO對象

public class User implements Serializable{

   

    private static final long serialVersionUID = 1738399846398814044L;

   

    private String userid;

    private String username;

    //注意這裏使用了Refrence及Lazyloading相關的引用

@Refrence

    private UserDetail userDeatil;

    public String getUserid() {

       return userid;

    }

    public void setUserid(String userid) {

       this.userid = userid;

    }

    public String getUsername() {

       return username;

    }

    public void setUsername(String username) {

       this. username = username;

    }

public UserDetail getUserDetail() {

       return userDetail;

    }

    public void setUserDetail (UserDetail userDetail) {

       this. userDetail = userDetail;

    }

}

 

//定義一個UserDetail PO對象

public class UserDetail implements Serializable{

   

    private static final long serialVersionUID = 1738399846398814045L;

   

    private String address;

   

public String getAddress() {

       return address;

    }

    public void setAddress (String address) {

       thisaddress = address;

    }

}

 

編寫Action,輸出List<User>,這裏使用僞碼

….

List<User> ls= userService.getUserList();

PrintWriterout = null;

       try {

           out = getResponse().getWriter();

           out.write(JSON.toJSONString(ls));

           out.flush();

       } catch (IOException e) {

           e.printStackTrace();

       } finally {

           out.close();

       }

 

編寫jquery ajax請求打出用戶列表

$.ajax({

       type:"GET",

       url:"/user/getuserlist", //假設這是你配置後的action地址

       dataType:"json",

       cache:false,

       success: function(users){

            var html=””;

            if(users.length>0){

           for(var i in users){

               html=html+”username:”+users[i]+username+” address:”+users[i].userDetail.address;

           }

          alert(html);

}

});

 

2、如何解決Refrence及LazyLoading引起的死循環問題?

從上述例子可以看到fastjson會正確取出userDetail下的address數據,實際上所有的json開源項目都支持這種關聯取出。但有時候我們並不需要userDetail下的數據,如果自動加載一堆無關的數據,甚至產生死循環,怎麼解決呢?

第一種辦法:

前面已經講過,加上transient關鍵字,如給User PO的UserDetail定義改成

private transient  UserDetailuserDeatil;

 

第二種辦法:

第一種辦法是通用的辦法,使用其他json開源項目,也可以達到效果,在FastJson下還可以使用@JSONField(serialize=false)

@JSONField(serialize=false)

private transient  UserDetailuserDeatil;

當然JSONField還有其他參數可以指定,以實現成員定製序列化,一般情況下,如果我們確定成員可以爲非序列化,首先建議使用transient。但有時候指定了transient會引起其他問題,假如User對象下有長字段remark,如果給remark指定了transient,那麼在比如使用Mongo數據庫情況下,會導致頁面提交的remark數據不能被保存到數據庫,其他沒有加transient關鍵字的字段能正常保存。這時就可以使用@JSONField來解決問題。

 

第三種辦法:

   假如有更進一步的優化,比如場景A的時候需要系列化remark,而在場景B的時候又不需要系列化,那就使用fastjson定製過濾器,fastjson可以按name、property、value三種過濾,以property例,重寫獲取List<user>這段僞碼:

….

List<User> ls= userService.getUserList();

PropertyFilter filter = new PropertyFilter() {

    publicboolean apply(Object source, String name, Object value) {

       if("remark".equals(name)) {

           return true;

        }

        returnfalse;

    }

};

 SerializeWriter sw = new SerializeWriter();

JSONSerializer serializer = new JSONSerializer(sw);

serializer.getPropertyFilters().add(filter);

serializer.write(ls);

PrintWriterout = null;

       try {

           out = getResponse().getWriter();

           out.write(sw.toString());

           out.flush();

       } catch (IOException e) {

           e.printStackTrace();

       } finally {

           out.close();

       }

這樣在碰到場景B時就使用第三種辦法把remark這個成員給過濾掉,在場景A的情況下不加過濾器即可。

更多fastjson信息可以查看http://code.alibabatech.com/wiki/display/FastJSON/Home

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章