(記錄)Jedis存放對象和讀取對象--Java序列化與反序列化

  1、理論分析javascript

  在學習Redis中的Jedis這一部分的時候,要使用到Protostuff(Protobuf的Java客戶端)這一序列化工具。一開始看到序列化這些字眼的時候,感受到一頭霧水。因而,參考了網上的不少資料,理解了Java序列化與反序列化(參考https://blog.csdn.net/wangloveall/article/details/7992448/),Protobuf的做用以及在Java中的使用方法。java

  1.Java序列化與反序列化是什麼:python

  Java序列化是指把Java對象轉換爲字節序列的過程;而Java反序列化是指把字節序列恢復爲Java對象的過程。git

  2.爲何須要Java序列化與反序列化github

  序列化的兩種很是重要的應用:redis

  • 使用序列化將對象集合保存到磁盤文件中,並按照它們被存儲的樣子獲取它們。
  • 經過網絡將對象集合傳送到另外一臺計算機上。

  3.爲何只能用序列化和反序列化算法

  • 在磁盤文件中,不能去保存和恢復對象的內存地址是由於對象被重載時,它可能佔據的是與原來徹底不一樣的內存地址。
  • 在網絡傳輸中,不一樣的處理器之間通訊時,對象佔據的內存地址也是徹底不一樣。

  4.序列化和反序列化的好處數據庫

  序列化就是每一個對象都是用一個序列號保存的,這就是這種機制被稱爲序列化的緣由。json

  5.實現Java對象序列化與反序列化的方法ubuntu

  • JDK庫中的序列化API實現二進制序列化
  • XML
  • JSON
  • Protostaff

  6.JDK庫中序列化與反序列化:

  (1)對象序列化包括以下步驟:

  • 建立一個對象輸出流,它能夠包裝一個其餘類的目標輸出流,如文件輸出流;
  • 經過對象輸出流的writeObject()方法寫對象。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("empoyee.dat"));
Employee harry = new Employee("Harry Hacker", 5000, 1989, 10, 1);
Maneger boss = new Manager("Carl Cracker", 7000, 1984, 12, 15);
oos.writeObject(harry);
oos.writeObject(boss);

  (2)對象反序列化包括以下步驟:

  • 建立一個對象輸入流,它能夠包裝一個其餘類型的源輸入流,如文件輸入流;
  • 經過對象輸入流的readObject()方法以這些對象被寫出的順序讀取對象並得到它們。
ObjectInputStream ois = new ObjectInputStream (new FileInputStream("empoyee.dat"));
Employee e1 = (Employee)ois.readObject();
Maneger e2 = (Manager)ois.readObject();

  (3)對於那麼須要序列化與反序列化的對象,對應的類必需要實現JDK庫的相關API,有如下三種方法:

  • 若Club類僅僅實現了Serializable接口,則能夠按照如下方式進行序列化和反序列化

    ObjectOutputStream採用默認的序列化方式,對Club對象的非transient的實例變量進行序列化。

    ObjcetInputStream採用默認的反序列化方式,對對Club對象的非transient的實例變量進行反序列化。

  • 若Club類僅僅實現了Serializable接口,而且還定義了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),則採用如下方式進行序列化與反序列化。

    ObjectOutputStream調用Student對象的writeObject(ObjectOutputStream out)的方法進行序列化。

    ObjectInputStream會調用Student對象的readObject(ObjectInputStream in)的方法進行反序列化。

  • 若Club類實現了Externalnalizable接口,且Club類必須實現readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,則按照如下方式進行序列化與反序列化。

    ObjectOutputStream調用Student對象的writeExternal(ObjectOutput out))的方法進行序列化。

    ObjectInputStream會調用Student對象的readExternal(ObjectInput in)的方法進行反序列化。

 

  2、示例程序分析

  1.測試環境:

  • 虛擬機ubuntu 16.04
  • Jedis版本:Jedis-2.9.0.jar
  • redis.conf配置文件寫入ubuntu系統ifconfig讀取的ip地址:192.168.131.130
  • 主機ping 192.168.131.130能夠ping通。  

  2.主機上運行eclipse程序,證實能夠鏈接到redis服務器

package bigjun.iplab.jedisConnectTest;

import redis.clients.jedis.Jedis;

public class JedisConnectTest {
    public static void main(String[] args) {
        @SuppressWarnings("resource")
        Jedis jedis = new Jedis("192.168.131.130");
        jedis.set("JedisConnectTest", "pass");
        String getResult = jedis.get("JedisConnectTest");
        System.out.println(getResult);
        
    }
}

  控制檯輸出pass,同時查看ubuntu系統上redis中成功存入redis數據。

  3.Jedis將對象序列化爲二進制的API:

public String set(final String key, String value)
public String set(final byte[] key, final byte[] value)
public byte[] get(final byte[] key)
public String get(final String key)

  有了這些API的支持,就能夠將Java對象序列化爲二進制,當應用須要獲取Java對象時,使用get(final byte[]key)函數將字節數組取出,而後反序列化爲Java對象便可。

  和不少NoSQL數據庫(例如Memcache、Ehcache)的客戶端不一樣,Jedis自己沒有提供序列化的工具,也就是說開發者須要本身引入序列化的工具。

  4.在測試主機能夠成功鏈接到虛擬機上的redis服務器而且能夠存讀數據後,考慮如何存讀對象。

  創建一個實現了Serializable接口的簡單對象類Club:

package bigjun.iplab.jdk;

import java.io.Serializable;
import java.util.Date;

public class Club implements Serializable {
    
    /**
     * 其實序列化的做用是能轉化成Byte流,而後又能反序列化成原始的類。能
     * 在網絡進行傳輸,也能夠保存在磁盤中,
     * 有了SUID以後,那麼若是序列化的類已經保存了在本地中,
     * 中途你更改了類後,SUID變了,那麼反序列化的時候就不會變成原始的類了,
     * 還會拋異常,主要就是用於版本控制。
     */
    private static final long serialVersionUID = 1L;
    
    private int id;
    private String name;
    private String info;
    private Date createDate;
    private int rank;
    
    public Club() {
        
    }
    
    public Club(int id, String name, String info, Date createDate, int rank) {
        super();
        this.id = id;
        this.name = name;
        this.info = info;
        this.createDate = createDate;
        this.rank = rank;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
    public Date getCreateDate() {
        return createDate;
    }
    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }
    public int getRank() {
        return rank;
    }
    public void setRank(int rank) {
        this.rank = rank;
    }
 

  5.使用JDK庫實現序列化和反序列化:

package bigjun.iplab.jdk;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

import redis.clients.jedis.Jedis;

public class JDKSerializetionUtil {

    public static void main(String[] args) {
        Jedis jedis = null;
        try {
            jedis = new Jedis("192.168.131.130");

            Club club = new Club();

            club.setId(1);
            club.setName("AC");
            club.setInfo("米蘭");
            club.setCreateDate(new Date());
            club.setRank(2);

            jedis.set("JDK".getBytes(), serialize(club));
            byte[] getByte = jedis.get("JDK".getBytes());
            Object getObject = unserizlize(getByte);
            if (getObject instanceof Club) {
                System.out.println(getObject);
                System.out.println(((Club) getObject).getId());
                System.out.println(((Club) getObject).getName());
                System.out.println(((Club) getObject).getInfo());
                System.out.println(((Club) getObject).getCreateDate());
                System.out.println(((Club) getObject).getRank());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    private static byte[] serialize(Object object) {
        ObjectOutputStream objectOutputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            byte[] getByte = byteArrayOutputStream.toByteArray();
            return getByte;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Object unserizlize(byte[] binaryByte) {
        ObjectInputStream objectInputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        byteArrayInputStream = new ByteArrayInputStream(binaryByte);
        try {
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            Object obj = objectInputStream.readObject();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

  輸出爲:

bigjun.iplab.jdk.Club@300ffa5d
1
AC
米蘭
Sun Jun 03 20:29:24 GMT+08:00 2018
2

  在虛擬機上運行get JDK獲得:

192.168.131.130:6379> get JDK
"\xac\xed\x00\x05sr\x00\x15bigjun.iplab.jdk.Club\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x05I\x00\x02idI\x00\x04rankL\x00\ncreateDatet\x00\x10Ljava/util/Date;L\x00\x04infot\x00\x12Ljava/lang/String;L\x00\x04nameq\x00~\x00\x02xp\x00\x00\x00\x01\x00\x00\x00\x02sr\x00\x0ejava.util.Datehj\x81\x01KYt\x19\x03\x00\x00xpw\b\x00\x00\x01c\xc5\x95\xa00xt\x00\x06\xe7\xb1\xb3\xe5\x85\xb0t\x00\x02AC"

  再來看一下序列化方法:

    private static byte[] serialize(Object object) {
        ObjectOutputStream objectOutputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            byte[] getByte = byteArrayOutputStream.toByteArray();
            return getByte;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

  ByteArrayOutputStream:

  ObjectOutputStream

  再來看一下反序列方法:

    private static Object unserizlize(byte[] binaryByte) {
        ObjectInputStream objectInputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        byteArrayInputStream = new ByteArrayInputStream(binaryByte);
        try {
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            Object obj = objectInputStream.readObject();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

  ByteArrayInputStream

  ObjectInputStream

  6.使用Xml實現序列化和反序列化

  首先,必需要在要被序列化的對象的類上註釋@XmlRootElement(name = "Club"),即:

package bigjun.iplab.xml;

import java.io.Serializable;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;

// Xml文件中的根標識,必需要代表這個元素,可讓對象和Xml之間方便轉換
@XmlRootElement(name = "Club") 
public class Club implements Serializable {  
  ...
}

  而後是在Jedis中利用Xml讀寫Club對象:

package bigjun.iplab.xml;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.Date;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import redis.clients.jedis.Jedis;

public class XMLSerializetionUtil {

    public static void main(String[] args) {
        Jedis jedis = null;
        try {
            jedis = new Jedis("192.168.131.130");

            Club club = new Club();

            club.setId(2);
            club.setName("RM");
            club.setInfo("皇馬");
            club.setCreateDate(new Date());
            club.setRank(1);

            jedis.set("XML", serialize(club));
            String getString = jedis.get("XML");
            Object getObject = unserizlize(Club.class, getString);
            if (getObject instanceof Club) {
                System.out.println(getObject);
                System.out.println(((Club) getObject).getId());
                System.out.println(((Club) getObject).getName());
                System.out.println(((Club) getObject).getInfo());
                System.out.println(((Club) getObject).getCreateDate());
                System.out.println(((Club) getObject).getRank());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    private static String serialize(Object object) {
        StringWriter stringWriter = null;
        try {
            stringWriter = new StringWriter();
            JAXBContext jContext = JAXBContext.newInstance(object.getClass());
            Marshaller marshaller = jContext.createMarshaller();
            marshaller.marshal(object, stringWriter);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return stringWriter.toString();
    }

    private static Object unserizlize(Class<Club> clazz, String xmlString) {

        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader stringReader = new StringReader(xmlString);
            xmlObject = unmarshaller.unmarshal(stringReader);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

}

  輸出爲:

bigjun.iplab.xml.Club@1f17ae12
2
RM
皇馬
Mon Jun 04 09:42:17 GMT+08:00 2018
1

  在虛擬機上運行get XML獲得:

"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Club><createDate>2018-06-04T09:42:17.343+08:00</createDate><id>2</id><info>\xe7\x9a\x87\xe9\xa9\xac</info><name>RM</name><rank>1</rank></Club>"

  再來分析一下序列化方法:

    private static String serialize(Object object) {
        StringWriter stringWriter = null;
        try {
            stringWriter = new StringWriter();
            JAXBContext jContext = JAXBContext.newInstance(object.getClass());
            Marshaller marshaller = jContext.createMarshaller();
            marshaller.marshal(object, stringWriter);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return stringWriter.toString();
    }

  再來分析一下反序列化方法:

    private static Object unserizlize(Class<Club> clazz, String xmlString) {

        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader stringReader = new StringReader(xmlString);
            xmlObject = unmarshaller.unmarshal(stringReader);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

  7.使用JSON實現序列化和反序列化

  Java下經常使用的JSON工具類庫主要有如下幾種:

  • JSON-lib
  • FastJson
  • Jackson
  • Gson

  1.以JSON-lib爲例:

  所需的jar包爲:

  

  Club類不須要添加任何註釋,直接看在Jedis中經過JSON讀寫Club對象類:

package bigjun.iplab.json;

import java.util.Date;

import net.sf.ezmorph.object.DateMorpher;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONUtils;
import redis.clients.jedis.Jedis;

public class JDKSerializetionUtil {

    public static void main(String[] args) {
        Jedis jedis = null;
        try {
            jedis = new Jedis("192.168.131.130");

            Club club = new Club();

            club.setId(3);
            club.setName("CLE");
            club.setInfo("騎士");
            club.setCreateDate(new Date());
            club.setRank(2);

            jedis.set("JSON", serialize(club));
            String getByte = jedis.get("JSON");
            Object getObject = unserizlize(getByte);
            if (getObject instanceof Club) {
                System.out.println(getObject);
                System.out.println(((Club) getObject).getId());
                System.out.println(((Club) getObject).getName());
                System.out.println(((Club) getObject).getInfo());
                System.out.println(((Club) getObject).getCreateDate());
                System.out.println(((Club) getObject).getRank());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    private static String serialize(Object object) {
        JSONObject jsonObject = JSONObject.fromObject(object);
        String getString = jsonObject.toString();
        return getString;

    }

    private static Object unserizlize(String jsonString) {
        new JSONObject();
        JSONObject jObject = JSONObject.fromObject(jsonString);
        JSONUtils.getMorpherRegistry().registerMorpher(new DateMorpher(new String[] { "MM/dd/yyyy HH:mm:ss" }));
        Object jsonObject = JSONObject.toBean(jObject, Club.class);
        return jsonObject;
    }

}

  輸出爲:

六月 04, 2018 11:02:31 上午 net.sf.json.JSONObject toBean
信息: Property 'day' of class java.util.Date has no write method. SKIPPED.
六月 04, 2018 11:02:31 上午 net.sf.json.JSONObject toBean
信息: Property 'timezoneOffset' of class java.util.Date has no write method. SKIPPED.
bigjun.iplab.json.Club@2a098129
3
CLE
騎士
Mon Jun 04 11:02:30 GMT+08:00 2018
2

  在Redis服務器所在的虛擬機上執行get JSON輸出爲:

192.168.131.130:6379> get JSON
"{\"createDate\":{\"date\":4,\"day\":1,\"hours\":11,\"minutes\":2,\"month\":5,\"seconds\":30,\"time\":1528081350946,\"timezoneOffset\":-480,\"year\":118},\"id\":3,\"info\":\"\xe9\xaa\x91\xe5\xa3\xab\",\"name\":\"CLE\",\"rank\":2}"

  分析使用JSON實現序列化代碼:將Java對象轉換爲JSON對象--將JSON對象轉換爲String類型的字符串。

    private static String serialize(Object object) {
        JSONObject jsonObject = JSONObject.fromObject(object);
        String getString = jsonObject.toString();
        return getString;
    }

  分析使用JSON實現反序列化代碼:將String類型的JSON字符串轉換爲JSON對象----將JSON對象轉換爲Java對象。

    private static Object unserizlize(String jsonString) {
        new JSONObject();
        JSONObject jObject = JSONObject.fromObject(jsonString);
     // 防止轉換時間錯誤 JSONUtils.getMorpherRegistry().registerMorpher(
new DateMorpher(new String[] { "MM/dd/yyyy HH:mm:ss" })); Object jsonObject = JSONObject.toBean(jObject, Club.class); return jsonObject; }

  2.以FastJson爲例:

  (1)FastJson介紹

  Fastjson是一個Java語言編寫的高性能功能完善的JSON庫。它採用一種假定有序快速匹配的算法,把JSON Parse的性能提高到極致,是目前Java語言中最快的JSON庫。Fastjson接口簡單易用,已經被普遍使用在緩存序列化、協議交互、Web輸出、Android客戶端等多種應用場景。

  (2)FastJson優勢:

  • FastJson數度快,不管序列化和反序列化,都是目前Java中最快的。
  • 功能強大(支持普通JDK類包括任意Java Bean Class、Collection、Map、Date或enum)。
  • 零依賴(沒有依賴其它任何類庫)

  (3)FastJson主要API

1. 將對象序列化成json字符串

String com.alibaba.fastjson.JSON.toJSONString(Object object)

2. 將json字符串反序列化成對象

<T> Project com.alibaba.fastjson.JSON.parseObject(String text, Class<T> clazz)

3. 將json字符串反序列化成JSON對象

JSONObject com.alibaba.fastjson.JSON.parseObject(String text)

4.根據key 獲得json中的json數組

JSONArray com.alibaba.fastjson.JSONObject.getJSONArray(String key)

5. 根據下標拿到json數組的json對象

JSONObject com.alibaba.fastjson.JSONArray.getJSONObject(int index)

6.. 根據key拿到json的字符串值

String com.alibaba.fastjson.JSONObject.getString(String key)

7. 根據key拿到json的int值

int com.alibaba.fastjson.JSONObject.getIntValue(String key)

8. 根據key拿到json的boolean值

boolean com.alibaba.fastjson.JSONObject.getBooleanValue(String key)

  (4)使用FastJson實如今Jedis中讀寫Club對象(FastJson提供了很完美的API,這裏就不用再多說了,直接使用便可)

  FastJson版本:fastjson-1.2.47.jar

package bigjun.iplab.json;

import java.util.Date;

import com.alibaba.fastjson.JSON;

import redis.clients.jedis.Jedis;

public class FastJsonSerializetionUtil {

    public static void main(String[] args) {
        Jedis jedis = null;
        try {
            jedis = new Jedis("192.168.131.130");

            Club club = new Club();

            club.setId(4);
            club.setName("GS");
            club.setInfo("勇士");
            club.setCreateDate(new Date());
            club.setRank(1);

            jedis.set("FastJson", serialize(club));
            String getByte = jedis.get("FastJson");
            Object getObject = unserizlize(getByte);
            if (getObject instanceof Club) {
                System.out.println(getObject);
                System.out.println(((Club) getObject).getId());
                System.out.println(((Club) getObject).getName());
                System.out.println(((Club) getObject).getInfo());
                System.out.println(((Club) getObject).getCreateDate());
                System.out.println(((Club) getObject).getRank());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    private static String serialize(Object object) {
        String getString = JSON.toJSONString(object);
        return getString;
    }

    private static Object unserizlize(String jsonString) {
        Object jsonObject = JSON.parseObject(jsonString, Club.class);
        return jsonObject;
    }

}

  輸出:

bigjun.iplab.json.Club@41975e01
4
GS
勇士
Mon Jun 04 11:25:04 GMT+08:00 2018
1

  虛擬機上執行get FastJson的輸出(和使用JSON-lib方式輸出的字符串明顯短了不少):

192.168.131.130:6379> get FastJson
"{\"createDate\":1528082704016,\"id\":4,\"info\":\"\xe5\x8b\x87\xe5\xa3\xab\",\"name\":\"GS\",\"rank\":1}"

  8.JSON與XML優缺點對比分析

  (1)JSON的優勢:

  • 與XML相比,JSON更加的簡潔,咱們能夠一眼就看出其中的內容,方便檢查排錯
  • JSON更加輕量級,不論是編寫,傳輸,仍是解析都更加高效
  • JSON在傳輸過程當中採用了壓縮技術,更加的節省寬帶
  • 衆多的語言支持,如javascript,python,C,C++等主流語言都支持
  • 由於JSON格式能直接爲服務器端代碼使用,大大簡化了服務器端和客戶端的代碼開發量,且完成任務不變,而且易於維護。

  (2)XML的優勢:

  • 格式統一,符合標準;
  • 容易與其餘系統進行遠程交互,數據共享比較方便

  (3)XML的缺點:

  • XML文件龐大,文件格式複雜,傳輸佔帶寬;
  • 服務器端和客戶端都須要花費大量代碼來解析XML,致使服務器端和客戶端代碼變得異常複雜且不易維護;
  • 客戶端不一樣瀏覽器之間解析XML的方式不一致,須要重複編寫不少代碼;
  • 服務器端和客戶端解析XML花費較多的資源和時間。

  9.使用Protostuff實現序列化與反序列化

  (1)Protobuf介紹

  Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,目前已經正在使用的有超過 48,162 種報文格式定義和超過 12,183 個 .proto 文件。他們用於 RPC 系統和持續數據存儲系統。

  Protocol Buffers 是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據串行化,或者說序列化。它很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。目前提供了 C++、Java、Python 三種語言的 API。

  (2)Protobuf優勢

  • 平臺無關,語言無關,可擴展;  
  • 提供了友好的動態庫,使用簡單;
  • 解析速度快,比對應的XML快約20-100倍;  
  • 序列化數據很是簡潔、緊湊,與XML相比,其序列化以後的數據量約爲1/3到1/10;
  • 獨立於語言,獨立於平臺,最最重要的是它的效率至關高,用protobuf序列化後的大小是json的10分之一,xml格式的20分之一,是二進制序列化的10分之一,

  (3)Protobuf主要流程

  須要本身寫一個.proto文件用來描述序列化的格式,而後用Protobuf提供的protoc工具將.proto文件編譯成一個Java文件,最後將該Java文件引入到項目中就能夠了。

  (4)Protostuff介紹

  google原生的protobuffer使用起來至關麻煩,首先要寫.proto文件,而後編譯.proto文件,生成對應的.java文件。protostuff基於Google Protobuf,好處就是不用本身寫.proto文件同時在幾乎不損耗性能的狀況下便可實現對象的序列化與反序列化。

  (5)使用Protostuff示例

  Protostuff版本:

  

  使用Protostuff實現Jedis中Club對象的讀取:

  • 代碼結構爲:

  

  序列化工具類ProtostuffSerializer 提供了序列化和反序列化方法:

package bigjun.iplab.protostuff;

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;

/**
 * 序列化和反序列化工具
 */
public class ProtostuffSerializer {
    private Schema<Club> schema = RuntimeSchema.createFrom(Club.class);
    
    // 序列化工具
    public byte[] seriable(final Club club) {
        final LinkedBuffer linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            return serializeInternal(club, schema, linkedBuffer);
        } catch (final Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            linkedBuffer.clear();
        }
    }
    
    // 實際序列化工具
    private <T> byte[] serializeInternal(final T source, final Schema<T> schema, final LinkedBuffer linkedBuffer) {
        return ProtostuffIOUtil.toByteArray(source, schema, linkedBuffer);
    }
    
    // 反序列化工具
    public Club deserialize(final byte[] bytes) {
        try {
            Club club = deserializeInternal(bytes, schema.newMessage(), schema);
            if (club != null) {
                return club;
            }
        } catch (final Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        return null;
    }
    
    // 實際反序列化工具
    private <T> T deserializeInternal(final byte[] bytes, final T result, final Schema<T> schema) {
        ProtostuffIOUtil.mergeFrom(bytes, result, schema);
        return result;
    }
}

  測試類:

package bigjun.iplab.protostuff;

import java.util.Date;

import redis.clients.jedis.Jedis;

public class ProtostuffSerializetionUtil {

    public static void main(String[] args) {
        Jedis jedis = null;
        try {
            // 生成Jedis對象
            jedis = new Jedis("192.168.131.130");
            // 生成序列化和反序列化工具類對象
            ProtostuffSerializer protostuffSerializer = new ProtostuffSerializer();
            // 定義實體對象
            Club club = new Club(5, "RNG", "皇族", new Date(), 1);
            
            // 序列化
            byte[] clubBytes = protostuffSerializer.serialize(club);
            // 將club對象寫入Redis
            jedis.set("Protostuff".getBytes(), clubBytes);
            
            // 從Redis中讀取表示club對象的字符數組
            byte[] getBytes = jedis.get("Protostuff".getBytes());
            // 反序列化
            Club getClubObject = protostuffSerializer.deserialize(getBytes); 
            
            if (getClubObject instanceof Club) {
                System.out.println(getClubObject);
                System.out.println(((Club) getClubObject).getId());
                System.out.println(((Club) getClubObject).getName());
                System.out.println(((Club) getClubObject).getInfo());
                System.out.println(((Club) getClubObject).getCreateDate());
                System.out.println(((Club) getClubObject).getRank());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
}

  輸出:

bigjun.iplab.protostuff.Club@ed17bee
5
RNG
皇族
Mon Jun 04 15:55:32 GMT+08:00 2018
1

  虛擬機上執行get Protostuff的輸出(能夠看出,長度在幾種序列化中最短):

192.168.131.130:6379> get Protostuff
"\b\x05\x12\x03RNG\x1a\x06\xe7\x9a\x87\xe6\x97\x8f!\xf3G\xcb\xc9c\x01\x00\x00(\x01"

  再來看一下序列化工具:

    // 序列化工具
    public byte[] serialize(final Club club) {
        final LinkedBuffer linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            return serializeInternal(club, schema, linkedBuffer);
        } catch (final Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            linkedBuffer.clear();
        }
    }

    // 實際序列化工具
    private <T> byte[] serializeInternal(final T source, final Schema<T> schema, final LinkedBuffer linkedBuffer) {
        return ProtostuffIOUtil.toByteArray(source, schema, linkedBuffer);
    }

  再看看一下反序列化工具:

// 反序列化工具
    public Club deserialize(final byte[] bytes) {
        try {
            Club club = deserializeInternal(bytes, schema.newMessage(), schema);
            if (club != null) {
                return club;
            }
        } catch (final Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        return null;
    }

    // 實際反序列化工具
    private <T> T deserializeInternal(final byte[] bytes, final T result, final Schema<T> schema) {
        ProtostuffIOUtil.mergeFrom(bytes, result, schema);
        return result;
    }

 

  代碼已上傳至GitHub:https://github.com/BigJunOba/JedisSerialization

相關文章
相關標籤/搜索