1 引入Hessian依賴
<!--hessian-->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
2 編寫Hessian序列化,反序列化方法,定義實體類 示例
public class HessianSerializerUtil {
public static <T> byte[] serialize(T obj) {
byte[] bytes = null;
// 1、創建字節輸出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 2、對字節數組流進行再次封裝
// step 1. 定義外部序列化工廠
//ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();
//extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());
//extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());
// step 2. 序列化工廠
//SerializerFactory serializerFactory = new SerializerFactory();
//serializerFactory.addFactory(extSerializerFactory);
HessianOutput hessianOutput = new HessianOutput(bos);
//hessianOutput.setSerializerFactory(serializerFactory);
try {
// 注意,obj 必須實現Serializable接口
hessianOutput.writeObject(obj);
bytes = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
public static <T> T deserialize(byte[] data) {
if (data == null) {
return null;
}
// 1、將字節數組轉換成字節輸入流
ByteArrayInputStream bis = new ByteArrayInputStream(data);
// step 1. 定義外部序列化工廠
//ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();
//extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());
//extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());
// step 2. 序列化工廠
//SerializerFactory serializerFactory = new SerializerFactory();
//serializerFactory.addFactory(extSerializerFactory);
HessianInput hessianInput = new HessianInput(bis);
//hessianInput.setSerializerFactory(serializerFactory);
Object object = null;
try {
object = hessianInput.readObject();
} catch (IOException e) {
e.printStackTrace();
}
return (T) object;
}
}
package cn.micai.base.io;
import java.io.Serializable;
/**
* 描述:
* <p>
*
* transient使用小結
* 1.一旦變量被transient修飾,變量將不再是對象持久化的一部分,該變量內容在序列化後無法獲得訪問。
* 2.transient關鍵字只能修飾變量,而不能修飾方法和類。注意,本地變量是不能被transient關鍵字修飾的。變量如果是用戶自定義類變量,則該類需要實現Serializable接口。
* 3.被transient關鍵字修飾的變量不再能被序列化,一個靜態變量不管是否被transient修飾,均不能被序列化。
*
* @author: 趙新國
* @date: 2018/6/7 12:10
*/
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private int employeeId;
private String employeeName;
/**
* 使用transient關鍵字,表示該字段不序列化
*/
private transient String department;
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public String toString() {
return "Employee{" +
"employeeId=" + employeeId +
", employeeName='" + employeeName + '\'' +
", department='" + department + '\'' +
'}';
}
}
hession 序列化的特點
- 1.一旦變量被transient修飾,變量將不再是對象持久化的一部分,該變量內容在序列化後無法獲得訪問。
- 2.transient關鍵字只能修飾變量,而不能修飾方法和類。被序列化的類需要實現Serializable接口。
- 3.一個靜態變量不管是否被transient修飾,均不能被序列化
- 4 final類型變量 不管是否被transient修飾,均可以被序列化。
- 5 Student類集成Teacher類,Teacher類中有跟Student類型相同且屬性名相同的字段name,接下來看代碼:
public class Person implements Serializable {
private static final long serialVersionUID = 2l;
private int gender;
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"gender='" + gender + '\'' +
'}';
}
}
public class Em extends Person {
private int gender;
public Em() {
}
@Override
public int getGender() {
return gender;
}
@Override
public void setGender(int gender) {
this.gender = gender;
//super.setGender(gender);
}
@Override
public String toString() {
return "Em{" +
"gender=" + gender +
'}';
}
}
測試類:
public class Set {
public static void main(String[] args) throws Exception{
Em person=new Em();
person.setGender(1);
FileOutputStream fos = new FileOutputStream("tempdata.ser");
Hessian2Output output = new Hessian2Output(fos);
output.writeObject(person);
output.close();
FileInputStream fis = new FileInputStream("tempdata.ser");
Hessian2Input input = new Hessian2Input(fis);
Em p = (Em) input.readObject();
System.out.println(p);
}
}
輸出結果爲:
Em{gender=0}
理論上輸出的結果應該爲“gender=1”,但現在爲gender=0,原因如下:
- hessian序列化的時候會取出對象的所有自定義屬性,相同類型的屬性是子類在前父類在後的順序;
- hessian在反序列化的時候,是將對象所有屬性取出來,存放在一個map中 key = 屬性名 value是反序列類,相同名字的會以子類爲準進行反序列化;
- 相同名字的屬性 在反序列化的是時候,由於子類在父類前面,子類的屬性總是會被父類的覆蓋,由於java多態屬性,在上述例子中父類 student.name = null。
得出結論,兩種解決辦法
1 使用hessian序列化時,一定要注意子類和父類不能有同名字段
2 在給子類賦值的時候,也給父類賦值。
@Override
public void setGender(int gender) {
this.gender = gender;
//super.setGender(gender);
}
- 反序列化的時候 類裏多了字段,會初始化成默認值,少了值,會自動忽略。
- 不須使用serialVersionUID 作爲版本標識。