1. 程式人生 > >分散式系列三: 物件序列化

分散式系列三: 物件序列化

序列化可以解決分散式系統節點間複雜物件傳輸的問題. 將物件狀態轉化為可儲存或可傳輸的過程叫序列化, 而反序列化是將其還原成物件的過程.

幾種序列化機制

JDK的序列化

Java預設的序列化要求實現Serializable介面.

缺點:

  1. 序列化的結果比較大, 佔用位元組多, 傳輸效率低
  2. 僅Java實現, 不能跨語言

WebService

基於XML格式的傳輸.

Json方式

缺點:

  1. 結果依然較大
  2. 效能低

二進位制傳輸

MessagePack Protocal Buffer

Java的預設方式

// 使用了lombok
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car implements Serializable{

    // 版本號, java通過此版本號是否一致判斷是否可以執行反序列化
    // 名稱的資料型別必須準確,否則只是相當於定義一個普通的靜態變數
    public static long serialVersionUID = -1244L;

    // 靜態變數不序列化
    public static int age = 10;

    // 用protobuffer的話, 需要field上加Protobuffer的註解
    @Protobuf(fieldType = FieldType.INT32,order = 1)
    private int wheels;
    @Protobuf(fieldType = FieldType.STRING,order = 2)
    private String name;

    // 瞬時變數, 不被序列化
    private transient String desc;

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //serializeCar();
        Car car = deSerializeCar();
        System.out.println(car.age);
        System.out.println(car.toString());
    }

    private static void serializeCar() throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("car")));
        Car car = new Car(4, "BMW", "fast....");
        objectOutputStream.writeObject(car);
        car.age = 12;
        objectOutputStream.close();
    }

    private static Car deSerializeCar() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream;
        objectInputStream = new ObjectInputStream(new FileInputStream(new File("car")));
        Car car = (Car) objectInputStream.readObject();
        return car;
    }
}
  1. static final long serialVersionUID = -124L; 序列化版本號, 一致的版本才可以反序列化
  2. 靜態變數不參與序列化
  3. transient 修飾的變數不序列化
  4. 父類實現序列化介面,子類會繼承; 子類實現但父類不實現, 則父類的欄位不被序列化(程式碼略)
  5. 序列化物件的儲存: 同一物件的序列化,第二次將只儲存第一個的引用及變化的部分,這樣可以節省空間(程式碼略)

常用序列化協議

  • Json: Json是比較流行的序列化機制, Spring 預設的json序列化是使用Jackson, 阿里的FastJson效率更高且更易於使用.
  • Protobuffer: 二進位制序列化有效能和傳輸方面的優勢. 還有MessagePackage
  • Hessian2, Dobbo使用此協議
  • XML
  • FST
// FastJson的序列化和反序列化
String strJson = JSON.toJSONString(object);
Object object = JSON.parse(text);

//Hessian的序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Hessian2Output hessian2Output = new Hessian2Output(byteArrayOutputStream);
hessian2Output.writeObject(object);

//Protobuffer的序列化
Codec<Car> carCodec = ProtobufProxy.create(Car.class, false);
byte[] bytes = carCodec.encode(object);

序列化需要引用相關的包, 下面列出幾個.

<!--jackson的序列化包-->
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>

<!--fastjson的序列化包-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.49</version>
</dependency>

<!--Protobuffer的序列化包,由百度封裝,增加了易用性-->
<dependency>
    <groupId>com.baidu</groupId>
    <artifactId>jprotobuf</artifactId>
    <version>2.2.5</version>
</dependency>

<!--hessian的序列化包-->
<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.51</version>
</dependency>