記得好久之前寫代碼的時候,每次新建一個實體都會下意識的繼承Serializable接口,大部分人都知道這是對對象的序列化,但是大家真的知道序列化嗎?這篇文章就簡單的說下java中的序列化,讓你更多的理解java這門語言。前端
關於上篇文章說的,在應用登陸前使用第三方的人機驗證,若是第三方的產品忽然出現故障,沒法使用,這種情況咱們應該怎麼應對,在團隊中咱們也討論過這種狀況,咱們的方案就是客戶端不直接的請求第三方,而是由後端服務器充當一箇中介的角色,起轉發做用,這樣在第三方出現問題,咱們服務器端會作處理,這也是不把雞蛋放在同一個籃子裏的思想。java
接下來,簡單的說下序列化,json
將數據對象轉換爲二進制流的過程就稱爲對象的序列化(Serialization),反過來,將二進制流轉換爲對象就是反序列化(Deserializable)。序列化的用處是什麼呢?共兩點:後端
一、數據持久化:在不少應用中,須要對好多對象進行序列化,存到物理硬盤,較長時間的保存,好比,Session對象,當有數萬用戶併發訪問的時候,就會有數萬的Session對象,內存會承受很大的壓力,這個時候,就會把一些對象先序列化到硬盤中,須要使用的時候再還原到內存中。序列化對象要保留充分的信息,用來恢復數據對象,可是爲了節約存儲空間和網絡帶寬,序列化出的二進制流要儘量小。安全
二、網絡傳輸:當兩個進程在互相通訊的時候,就會進行數據傳輸,不論是何種類型的數據,都必需要轉成二進制流來傳輸,接受方收到後再轉爲數據對象。bash
重點來了,序列化在代碼中是怎麼實現的呢?如下介紹三種:服務器
一、java原生序列化:java類經過實現Serializable接口來實現。這個接口沒有任何方法,只是標識,java序列化保留了對象的元數據,以及對象數據,兼容性最好,可是不支持跨語言,性能也通常。網絡
public class BaseEntity implements Serializable {
private static final long serialVersionUID = -7333816285916354999L;
private Long id;
public BaseEntity() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
}
複製代碼
實現這個接口,idea會給你一個警告,它會建議你設置一個serialVersionUID,若是你不設置,編譯器會根據類的內部實現,包括類名、接口名、方法和屬性來自動生成serialVersionUID 若是類的源碼有修改,從新編譯後這個值也會變化。架構
在修改類的時候,咱們要根據兼容性來決定是否修改serialVersionUID,若是是兼容性質的升級,不建議修改,由於可能會反序列化失敗。若是是不兼容的,就須要修改,避免反序列化變得混亂。併發
java原生序列化,在反序列化的時候不會調用類的無參構造方法,而是調用native方法將屬性賦值爲對應類型的初始值。
最後,基於性能及兼容性,不推薦使用。
二、Hessian序列化:Hessian序列化是一種支持動態類型、跨語言、基於對象傳輸的網絡協議,java對象序列化後的二進制流,能夠被其餘語言反序列化。它的特性:
自描述序列化類型,不依賴外部描述文件或接口定義,用一個字節表示經常使用的基礎類型,極大縮短二進制流;
語言無關,支持腳本語言。
協議簡單,比java原生的要高效。
須要注意一點:Hessian會把複雜對象全部屬性存儲在一個Map中進行序列化,因此在父類和子類含有相同字段的狀況下,先序列化子類,後序列化父類,這樣的結果是子類的同名屬性會被父類覆蓋掉。
如下是代碼實現
/**
* Hessian實現序列化
*
* @param TestClass
* @return
* @throws IOException
*/
private static byte[] serialize(TestClass TestClass) {
ByteArrayOutputStream byteArrayOutputStream = null;
HessianOutput hessianOutput = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
// Hessian的序列化
hessianOutput = new HessianOutput(byteArrayOutputStream);
hessianOutput.writeObject(TestClass);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
hessianOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
複製代碼
三、JSON序列化:
JSON是一種輕量級的數據交換格式,這種序列化方式就是講數據對象轉換爲JSON字符串。在序列化的過程當中捨棄了類型信息。反序列化是隻有在提供了類型信息的狀況下才能完成。
public static <T> T fromJson(String json, Class<T> type) {
if (json != null && !json.equals("")) {
try {
return getObjectMapper().readValue(json, type);
} catch (Exception var3) {
var3.printStackTrace();
return null;
}
} else {
return null;
}
}
複製代碼
相信大部分讀者的公司和前端和客戶端數據的交互格式都是JSON吧,由於JSON的這種格式可讀性較好,並且也方便調試。
序列化一般會用於網絡傳輸數據對象,而對象中經常會含有敏感數據,因此黑客經常會攻擊這點,攻擊手段一般是利用反序列化過程構造惡意代碼,怎麼應對這種狀況呢?可使用transient關鍵字來修飾這個屬性,這樣在反序列化以後該屬性就會爲空,若是必定要傳遞的話,可使用對稱加密或非對稱加密獨立傳輸,在數據傳輸的問題上,咱們必定要具有安全意識。
但願看完這篇文章的你能有所收穫。
分享如下本身的思考:「對於用戶來講,系統太靈活是他們的負擔,意味着他們要作更多的選擇,對於技術人員來講,架構靈活能夠應對更多的運營策略。怎樣折中,是個問題。」
這樣的分享我會一直持續,你的關注、轉發和點贊是對我最大的支持,感謝。
關注公衆號,最新文章會出如今那裏哦