netty系列之:使用Jboss Marshalling来序列化java对象
简介
在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/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
netty系列之:使用Jboss Marshalling来序列化java对象的更多相关文章
- netty: 编解码之jboss marshalling, 用marshalling进行对象传输
		jboss marshalling是jboss内部的一个序列化框架,速度也十分快,这里netty也提供了支持,使用十分方便. TCP在网络通讯的时候,通常在解决TCP粘包.拆包问题的时候,一般会用以下 ... 
- FastJson只序列化java对象的部分属性
		public class Student { private int id; private String name; private int age; //get set方法略 } 如下方法: St ... 
- netty 的 JBoss Marshalling 编码解码
		一. JBoss Marshalling 简介. JBoss Marshalling 是一个Java 对象序列化包,对 JDK 默认的序列化框架进行了优化,但又保持跟 Java.io.Serializ ... 
- 【转】Netty系列之Netty编解码框架分析
		http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称 ... 
- Netty系列之Netty编解码框架分析
		1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decod ... 
- Netty学习(九)-Netty编解码技术之Marshalling
		前面我们讲过protobuf的使用,主流的编解码框架其实还有很多种: ①JBoss的Marshalling包 ②google的Protobuf ③基于Protobuf的Kyro ④Apache的Thr ... 
- netty权威指南学习笔记八——编解码技术之JBoss Marshalling
		JBoss Marshalling 是一个java序列化包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调参数和附加特性,这些参数 ... 
- Netty5+Jboss(Marshalling)完成对象序列化传输
		TCP在网络通讯的时候,通常在解决TCP粘包.拆包问题的时候,一般会用以下几种方式: 1. 消息定长 例如每个报文的大小固定为200个字节,如果不够,空位补空格: 2. 在消息尾部添加特殊字符进行分割 ... 
- netty系列之:netty对marshalling的支持
		目录 简介 netty中的marshalling provider Marshalling编码器 Marshalling编码的另外一种实现 总结 简介 在之前的文章中我们讲过了,jboss marsh ... 
随机推荐
- idea常见设置一
			1.顶部执行栏调整 原: 设置:勾选view==>toolbar 后: 这个一看其实没有什么太大的作用,但是你看这个按钮 这个按钮就是File==>Settings,这样会稍微方便点,只要 ... 
- instanceof关键字使用的方法(解决转型异常ClassCastException)
			一丶问题显现: 当你是父类的情况下,像使用子类的特定功能,就需要向下转型,但向下转型有可能会报错(ClassCastException) 而instanceof关键字就是解决异常的小能手,他能判断是否 ... 
- weevely使用小结
			Weevely 写在前面 由于比赛不确定会不会提供菜刀或者蚁剑,这里我稍微对weevely进行简单介绍一下,具体还是请看官方文档,官方文档讲的很详细(前提你英语嘚不错) 官方文档:https://gi ... 
- LQR (线性二次型调节器)的直观推导及简单应用
			转自:https://blog.csdn.net/heyijia0327/article/details/39270597 本文主要介绍LQR的直观推导,说明LQR目标函数J选择的直观含义以及简单介绍 ... 
- BGD(批量梯度下降)--学习笔记
			函数凸凹性: 用到的范数知识: 详细解释:每一个元素的平方再开方.补充损失函数: Huber Loss知识点 loss函数可以通过loss参数进行设置.SGDRegressor支持以下的loss函数: ... 
- 制作任意波形发生器MAX038
- 快如闪电,触控优先。新一代的纯前端控件集 WijmoJS发布新版本了
			全球最大的控件提供商葡萄城宣布,新一代纯前端控件 WijmoJS 发布2018 v1 版本,进一步增强产品功能,并支持在 Npm 上的安装和发布,极大的提升了产品的易用性. WijmoJS 是用 Ty ... 
- Android Studio连接SQLite数据库与SQLite Studio实时同步的实现
			最近学习用到了android开发连接数据库这一块,发现连接成功后,都要先访问安卓项目的数据库路径data/data/项目/databases,然后把对应的db文件拷出来,再在SQLite的可视化工具中 ... 
- java中downcast向下转型到底有什么用
			What is the point of downcast? 当一个方法只有子类才有,马克-to-win:不是说基类和子类都有,开始时又是基类指针指向派生类,这时就需要downcast, see th ... 
- Typora 设置图片自动上传
			使用 PicGo-Core(command line) 下载 PicGo-Core 依次点击 文件 -> 偏好设置 -> 图像 来到下图所示界面: 点击①位置选择 PicGo-Gore(c ... 
