通讯协议序列化解读(二) protostuff详解教程
上一篇文章 通讯协议序列化解读(一):http://www.cnblogs.com/tohxyblog/p/8974641.html
前言:上一面文章我们介绍了java序列化,以及谷歌protobuf,但是由于protobuf的使用起来并不像其他序列化那么简单(首先要写.proto文件,然后编译.proto文件,生成对应的.java文件),所以即使他是如何的优秀,也还是没能抢占json的份额。
这篇文章我们要介绍的是一款基于protobuf的java序列化协议——prorostuff,在java端能极大的简便使用,而且反序列化可由protobuf完成(那么前端就可以用其他语言的protobuf解码)。
一、protostuff介绍
protostuff 基于Google protobuf,但是提供了更多的功能和更简易的用法。其中,protostuff-runtime 实现了无需预编译对java bean进行protobuf序列化/反序列化的能力。protostuff-runtime的局限是序列化前需预先传入schema,反序列化不负责对象的创建只负责复制,因而必须提供默认构造函数。此外,protostuff 还可以按照protobuf的配置序列化成json/yaml/xml等格式。
在性能上,protostuff不输原生的protobuf,甚至有反超之势。
二、Protostuff特征
支持protostuff-compiler产生的消息
支持现有的POJO
支持现有的protoc产生的Java消息
与各种移动平台的互操作能力(Android、Kindle、j2me)
支持转码
三、工具类实现
导包:
<!-- //protostuff序列化 -->
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.0.8</version>
</dependency>
<!-- Objenesis -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>2.1</version>
</dependency>
工具类:
package com.result.base.tools; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd; import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtobufIOUtil;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema; /**
* @author 作者 huangxinyu
* @version 创建时间:2018年1月9日 下午7:41:24
* Protostuff序列化工具
*/
public class SerializationUtil {
private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<>(); private static Objenesis objenesis = new ObjenesisStd(true); private SerializationUtil() {
} @SuppressWarnings("unchecked")
private static <T> Schema<T> getSchema(Class<T> cls) {
Schema<T> schema = (Schema<T>) cachedSchema.get(cls);
if (schema == null) {
schema = RuntimeSchema.createFrom(cls);
if (schema != null) {
cachedSchema.put(cls, schema);
}
}
return schema;
} @SuppressWarnings("unchecked")
public static <T> String serializeToString(T obj) {
Class<T> cls = (Class<T>) obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema<T> schema = getSchema(cls);
return new String(ProtobufIOUtil.toByteArray(obj, schema, buffer), "ISO8859-1");
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
buffer.clear();
}
} public static <T> T deserializeFromString(String data, Class<T> cls) {
try {
T message = (T) objenesis.newInstance(cls);
Schema<T> schema = getSchema(cls);
ProtobufIOUtil.mergeFrom(data.getBytes("ISO8859-1"), message, schema);
return message;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
} @SuppressWarnings("unchecked")
public static <T> byte[] serializeToByte(T obj) {
Class<T> cls = (Class<T>) obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema<T> schema = getSchema(cls);
return ProtobufIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
buffer.clear();
}
} public static <T> T deserializeFromByte(byte[] data, Class<T> cls) {
try {
T message = (T) objenesis.newInstance(cls);
Schema<T> schema = getSchema(cls);
ProtobufIOUtil.mergeFrom(data, message, schema);
return message;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}
四、性能测试
4.1 测试环境

xstraem版本:1.3.1
protobuf-java版本:3.0.0-alpha-2
java版本:1.7
-Xms2048m
-Xmx2048m
4.2 测试工具
用时: 控制台输出时间
CPU&内存: jconsole
文件大小: 文件属性
4.3 说明
测试中,xml和protoBuf和protostuff三种测试所使用的JavaBean所拥有的字段类型相同、字段数量相同(约28个)、字段所附的值相同、都包含有一个List<String>字段,用List字段的size来控制JavaBean对象的大小。本次测试中size=100
4.4 结果
测试A:10000个对象
|
xstream |
protobuf |
protostuff |
||
|
序列化 |
用时(ms) |
2399 |
648 |
261 |
|
占用的CPU(%) |
24.2 |
12.3 |
3.4 |
|
|
占用的内存(M) |
154 |
235 |
92 |
|
|
每个文件大小(byte) |
2822 |
574 |
574 |
|
|
反序列化 |
用时(ms) |
3378 |
167 |
224 |
|
占用CPU(%) |
15.9 |
14.2 |
6.1 |
|
|
占用内存(M) |
248 |
307 |
164 |
|
|
备注:10000个对象 |
||||
测试B:25000个对象
|
xstream |
protobuf |
protostuff |
||
|
序列化 |
用时(ms) |
4161 |
767 |
293 |
|
占用的CPU(%) |
31.2 |
14.6 |
4.7 |
|
|
占用的内存(M) |
495 |
228 |
194 |
|
|
每个文件大小(byte) |
2822 |
574 |
574 |
|
|
反序列化 |
用时(ms) |
6941 |
252 |
393 |
|
占用CPU(%) |
31.9 |
21.9 |
8.1 |
|
|
占用内存(M) |
411 |
382 |
348 |
|
|
备注:25000个对象 |
||||
测试C:100000个对象
|
xstream |
protobuf |
protostuff |
||
|
序列化 |
用时(ms) |
12867 |
3070 |
704 |
|
占用的CPU(%) |
42.5 |
44.9 |
22.3 |
|
|
占用的内存(M) |
1098 |
1058 |
572 |
|
|
每个文件大小(byte) |
2822 |
574 |
574 |
|
|
反序列化 |
用时(ms) |
24442 |
4540 |
1522 |
|
占用CPU(%) |
38.8 |
68.2 |
24.1 |
|
|
占用内存(M) |
2215 |
597 |
870 |
|
|
备注:50000个对象 |
||||
引用最后一组数据的直方图:



4.5 结论
1、序列化:
1.1、速度上:protostuff比protobuf快3倍左右,protobuf比xml快4-5倍,该倍数随着序列化对象的增加,基本保持不变。
1.2、CPU上:protostuff占用最少,protobuf其次,xml最后。
1.3、内存上:protostuff占用最少,protobuf其次,xml最后。
1.4、生成文件大小:protostuff占用最少,protobuf其次,xml最后,前面两者是后者的1/4左右。
2、反序列化
2.1、速度上:在反序列化对象数量较少的情况下,protobuf比protostuff快1/4左右,比xml快10+倍。但随着对象数量的增加,protobuf发生了速率明显变慢的情况!从而被protostuff赶超。
2.2、CPU上:protostuff占用最少,protobuf其次,xml最后。
2.3、内存上:protostuff占用最少,protobuf其次,xml最后。
3、总结
在各个方面上,protostuff的优势非常面试,而protobuf也不弱,考虑用来代替xml。
通讯协议序列化解读(二) protostuff详解教程的更多相关文章
- 通讯协议序列化解读(一) Protobuf详解教程
前言:说到JSON可能大家很熟悉,是目前应用最广泛的一种序列化格式,它使用起来简单方便,而且拥有超高的可读性.但是在越来越多的应用场景里,JSON冗长的缺点导致它并不是一种最优的选择. 一.常用序列化 ...
- 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码
详解C#泛型(二) 一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...
- 搞懂分布式技术4:ZAB协议概述与选主流程详解
搞懂分布式技术4:ZAB协议概述与选主流程详解 ZAB协议 ZAB(Zookeeper Atomic Broadcast)协议是专门为zookeeper实现分布式协调功能而设计.zookeeper主要 ...
- ViewPager 详解(二)---详解四大函数
前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合Android的API说明 ...
- 转载 C# 序列化与反序列化意义详解
C# 序列化与反序列化意义详解 总结: ①序列化基本是指把一个对象保存到文件或流中,比如可以把文件序列化以保存到Xml中,或一个磁盘文件中②序列化以某种存储形式使自定义对象持久化: ③将对象从一个地方 ...
- HTTP协议头部与Keep-Alive模式详解
HTTP协议头部与Keep-Alive模式详解 .什么是Keep-Alive模式? 我们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器 ...
- iOS 开发之照片框架详解之二 —— PhotoKit 详解(下)
本文链接:http://kayosite.com/ios-development-and-detail-of-photo-framework-part-three.html 这里接着前文<iOS ...
- iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)
转载自:http://kayosite.com/ios-development-and-detail-of-photo-framework-part-two.html 一. 概况 本文接着 iOS 开 ...
- Hexo系列(二) 配置文件详解
Hexo 是一款优秀的博客框架,在使用 Hexo 搭建一个属于自己的博客网站后,我们还需要对其进行配置,使得 Hexo 更能满足自己的需求 这里所说的配置文件,是位于站点根目录下的 _config.y ...
随机推荐
- 云+社区技术沙龙:Kafka meetup 深圳站报名开启
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 如果说 2018 年是技术大爆炸年,那么 Apache Kafka 绝对是其中闪亮的新星. 自Kafka 从首发之日起,已经走过了快八个年头 ...
- redis中的aof模式,产生的是增量数据,还是全量数据?
先说答案:全量数据. 1.修改redis.conf,开启rdb,禁用aof 上面这个是持久化文件的路径,我们ll看下: 2.启动redis后,cli查看里面的key [root@mini1 redis ...
- DOM节点删除之empty和remove区别
要移除页面上节点是开发者常见的操作,jQuery提供了几种不同的方法用来处理这个问题,这里我们开仔细了解下empty和remove方法 empty 顾名思义,清空方法,但是与删除又有点不一样,因为它只 ...
- Ecplise 配置本地 https 测试
今天做项目,需要关联Office 365.为了实现Office365的用户邮件信息与项目的实时同步,需要建立webhook订阅. Office 365 API 连接 https://graph.mi ...
- POJ-3723 Conscription---最大权森林---最小生成树
题目链接: https://vjudge.net/problem/POJ-3723 题目大意: 需要征募女兵N人, 男兵M人. 每征募一个人需要花费10000美元. 带式如果已经征募的人中有一些关系亲 ...
- html如何实现的
超文本标记语言是标准通用标记语言下的一个应用,也是一种规范,一种标准,它通过标记符号来标记要显示的网页中的各个部分.网页文件本身是一种文本文件,通过在文本文件中添加标记符,可以告诉浏览器如何显示其中的 ...
- Mybatis-简单基于源码了解获取动态代理对象
这是我们要测试的代码 OderDao就是我们要需要获取的对象. 首先我们根据传入的参数,进入SqlSessionFactoryBuilder 中的对应的build 方法,第一步创键XMLConfigB ...
- PHP面向对象-看父类调用子类方法
大部分面向对象编程语言中,父类是不允许调用子类的方法的,但是PHP中可以 1.父类调用子类方法示例 class A { public function testa() { $this->test ...
- 【实验吧】CTF_Web_简单的SQL注入之3
实验吧第二题 who are you? 很有意思,过两天好好分析写一下.简单的SQL注入之3也很有意思,适合做手工练习,详细分析见下. http://ctf5.shiyanbar.com/web/in ...
- Centos常用命令之:搜索
在linux中,所有的文件都是以目录树的形式存在的.而每个发行版的文件存放之间又会有些差别. 这时候,如果我们想看某个命令或者文档的时候就必须先通过某种方式找到改文档的所在位置. 在linux中提供了 ...