簡介
在JAVA程式中經常會用到序列化的場景,除了JDK自身提供的Serializable之外,還有一些第三方的產品可以實現對JAVA物件的序列化。其中比較有名的就是Google protobuf。當然,也有其他的比較出名的序列化工具,比如Kryo和JBoss Marshalling。
今天想給大家介紹的就是JBoss Marshalling,為什麼要介紹JBoss Marshalling呢?
用過google protobuf的朋友可能都知道,雖然protobuf好用,但是需要先定義序列化物件的結構才能生成對應的protobuf檔案。如果怕麻煩的朋友可能就不想考慮了。
JBoss Marshalling就是在JDK自帶的java.io.Serializable中進行優化的一個序列化工具,用起來非常的簡單,並且和java.io.Serializable相容,所以是居家必備開發程式的好幫手。
根據JBoss官方的介紹,JBoss Marshalling和JDK java.io.Serializable相比有兩個非常大的優點,第一個優點就是JBoss Marshalling解決了java.io.Serializable中使用的一些不便和問題。第二個優點就是JBoss Marshalling完全是可插拔的,這樣就提供了對JBoss Marshalling框架進行擴充套件的可能,那麼一起來看看JBoss Marshalling的使用吧。
新增JBoss Marshalling依賴
如果想用JBoss Marshalling,那麼第一步就是新增JBoss Marshalling的依賴。
很奇怪的是如果你到JBoss Marshalling的官網上,可能會發現JBoss Marshalling很久都沒有更新了,它的最新版本還是2011-04-27年出的1.3.0.CR9版本。
但是不要急,如果你去maven倉庫搜一下,會發現最新的版本是2021年5月發行的2.0.12.Final版本。
所以這裡我們就拿最新的2.0.12.Final版本為例進行講解。
如果仔細觀察JBoss Marshalling的maven倉庫,可以看到JBoss Marshalling包含了4個依賴包,分別是JBoss Marshalling API,JBoss Marshalling River Protocol,JBoss Marshalling Serial Protocol和JBoss Marshalling OSGi Bundle。
JBoss Marshalling API是我們在程式中需要呼叫的API介面,這個是必須要包含的。JBoss Marshalling River Protocol和JBoss Marshalling Serial Protocol是marshalling的兩種實現方式,可以根據需要自行取捨。
JBoss官網並沒有太多關於這兩個序列化實現的細節,我只能說,根據我的瞭解river的壓縮程度更高。其他更多細節和實現可能只有具體閱讀原始碼才知道了。
JBoss Marshalling OSGi Bundle是一個基於OSGi的可插拔的框架。
如果我們只是做物件的序列化,那麼只需要使用JBoss Marshalling API和JBoss Marshalling River Protocol就行了。
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling</artifactId>
<version>2.0.12.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-river</artifactId>
<version>2.0.12.Final</version>
</dependency>
JBoss Marshalling的使用
新增了依賴之後,我們就可以開始使用JBoss Marshalling了。JBoss Marshalling的使用非常簡單,首先我們要根據選擇的marshalling方式建立MarshallerFactory:
// 使用river作為marshalling的方式
MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("river");
這裡我們選擇使用river作為marshalling的序列化方式。
有了MarshallerFactory,我們還需要一個MarshallingConfiguration為MarshallerFactory提供一些必要的序列化引數。
一般來說,我們可以控制MarshallingConfiguration的下面一些屬性:
MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(4);
configuration.setClassCount(10);
configuration.setBufferSize(8096);
configuration.setInstanceCount(100);
configuration.setExceptionListener(new MarshallingException());
configuration.setClassResolver(new SimpleClassResolver(getClass().getClassLoader()));
setVersion是設定使用的marshalling protocol的版本號,這個版本號非常重要,因為依賴的protocol實現可能根據會根據需要進行序列化實現的升級,可能產生不相容的情況。通過設定版本號,可以保證升級之後的protocol也能相容之前的序列化版本。
setClassCount是預設要序列化物件中的class個數。
setInstanceCount是預設序列化物件中的class例項個數。
setBufferSize設定讀取資料的buff大小,通過調節這個屬性可以調整序列化的效能。
setExceptionListener新增序列化異常的時候的異常監聽器。
setClassResolver用來設定classloader。
JBoss Marshalling的強大之處在於我們在序列化的過程中還可以對物件進行攔截,從而進行日誌輸出或者其他的業務操作。
configuration提供了兩個方法,分別是setObjectPreResolver和setObjectResolver。
這兩個方法接受一個ObjectResolver物件,可以用來對物件進行處理。
兩個方法的不同在於執行的順序,preResolver在所有的resolver之前執行。
做好上面的配置之後,我們就可以正式開始編碼了。
final Marshaller marshaller = marshallerFactory.createMarshaller(configuration);
try(FileOutputStream os = new FileOutputStream(fileName)){
marshaller.start(Marshalling.createByteOutput(os));
marshaller.writeObject(obj);
marshaller.finish();
}
上面的例子中,通過呼叫marshaller的start方法開啟序列化,然後呼叫marshaller.writeObject寫入物件。
最後呼叫marshaller.finish結束序列化。
整個序列化的程式碼如下所示:
public void marshallingWrite(String fileName, Object obj) throws IOException {
// 使用river作為marshalling的方式
MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("river");
// 建立marshalling的配置
MarshallingConfiguration configuration = new MarshallingConfiguration();
// 使用版本號4
configuration.setVersion(4);
final Marshaller marshaller = marshallerFactory.createMarshaller(configuration);
try(FileOutputStream os = new FileOutputStream(fileName)){
marshaller.start(Marshalling.createByteOutput(os));
marshaller.writeObject(obj);
marshaller.finish();
}
}
public static void main(String[] args) throws IOException {
MarshallingWriter writer = new MarshallingWriter();
Student student= new Student("jack", 18, "first grade");
writer.marshallingWrite("/tmp/marshall.txt",student);
}
非常的簡潔明瞭。
注意,這裡我們序列化了一個Student物件,這個物件一定要實現java.io.Serializable介面,否則會丟擲型別下面的異常:
Exception in thread "main" java.io.NotSerializableException:
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:274)
at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58)
at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111)
接下來就是序列化的反向動作反序列化了。
程式碼很簡單,我們直接上程式碼:
public void marshallingRead(String fileName) throws IOException, ClassNotFoundException {
// 使用river協議建立MarshallerFactory
MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("river");
// 建立配置檔案
MarshallingConfiguration configuration = new MarshallingConfiguration();
// 使用版本號4
configuration.setVersion(4);
final Unmarshaller unmarshaller = marshallerFactory.createUnmarshaller(configuration);
try(FileInputStream is = new FileInputStream(fileName)){
unmarshaller.start(Marshalling.createByteInput(is));
Student student=(Student)unmarshaller.readObject();
log.info("student:{}",student);
unmarshaller.finish();
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
MarshallingReader reader= new MarshallingReader();
reader.marshallingRead("/tmp/marshall.txt");
}
執行上面的程式碼,我們可能得到下面的輸出:
[main] INFO c.f.marshalling.MarshallingReader - student:Student(name=jack, age=18, className=first grade)
可見讀取序列化的物件已經成功。
總結
以上就是JBoss Marshalling的基本使用。通常對我們程式設計師來說,這個基本的使用已經足夠了。除非你有根據複雜的序列化需求,比如物件中的密碼需要在序列化的過程中進行替換,這種需求可以使用我們前面提到的ObjectResolver來實現。
本文的例子可以參考:learn-netty4
本文已收錄於 http://www.flydean.com/17-jboss-marshalling/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!