java序列化/反序列化xstream、protobuf、protostuff 简单使用

背景

        项目中http通信离不开对象的序列化和反序列化,通过序列化技术,可以夸语言实现数据的传输,例如把一个对象序列化后的二进制数据、xml格式数据存在文本文件,下次通过读取文件,然后反序列化一下即可重新生成该对象,抑或通过网络把序列化后的数据传输到另一个终端,对方通过反序列化后也可以重新复制出一个大概相同的对象出来。

        在一般项目中,xml是一个不错的选择,例如微信公众平台的大多数接口,就是使用xml技术来序列化传输的,学习成本低,可读性高,方便调试,可以直接在浏览器查看结果等等都是他的优点,对于对速度要求不高的系统来说,的确是一种不错的选择。但如果系统对序列化效率要求很高,例如想比xml快上10倍?那么可能就得考虑换成其他技术了,例如——protobuf。

        protobuf是谷歌推出的与语言无关、平台无关的通信协议,一个对象经过protobuf序列化后将变成二进制格式的数据,所以他可读性差,但换来的是占用空间小,速度快。使用protobuf要先使用特定的语法编写一个.proto文件,该文件与语言无关,然后使用特殊的编译器对该文件进行编译,生成与语言相关的文件,如java,那么将生成java的类,该类不仅有我们自己定义的属性,还提供了序列化,反序列化等其他方法。直接把该类copy到项目中,就可以使用了。不过缺点是,假如我们是数据的发送方,那么接受方也要有一个通过相同的.proto编译出来的“类”(假设对方使用java语言),才可以顺利地进行反编译。这样一来,假如我们对proto 2.6版本的编辑器对.proto文件进行编译,而对方使用的是2.3版本的编译器进行编译,那么编译出来的类是不一样的,且两个版本互不兼容。所以两方的版本要保持一致。这么一来,假如一方升级,但没及时通知另一方,那么可能导致对方无法反序列化!这个缺点也是不小的。

        针对以上缺点,一个基于protobuf的产品——protostuff诞生了,protostuff不需要依赖.proto文件,他可以直接对普通的javabean进行序列化、反序列化的操作,而效率上甚至比protobuf还快,不过使用protostuff的话可不可以xstream那样自定义转换器,这个还没研究过,如果有人研究过得,不妨留下评论。

使用xstream

1.准备jar包

<!-- xstream -->
<dependency>
	<groupId>com.thoughtworks.xstream</groupId>
	<artifactId>xstream</artifactId>
	<version>1.3.1</version>
</dependency>

2.编写实体类

package test;
/**
 * 序列化实体类
 */
public class Person {
	private String name;
	private Integer age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@Override
	public String toString(){
		return "name=" + this.name + ", age=" + this.age;
	}
}

3.序列化&反序列化

package test;

import com.thoughtworks.xstream.XStream;

public class Test {
	public static void main(String[] args) {
		Person person = new Person();
		person.setName("张三");
		person.setAge(100);
		String xml = serializeXML(person);
		System.out.println("----------序列化---------");
		System.out.println(xml);
		System.out.println("----------反序列化---------");
		System.out.println(deserializeXML(xml));
	}
	public static String serializeXML(Person person) {
		XStream xs = new XStream();
		xs.alias("Person", Person.class);
		return xs.toXML(person);
	}
	public static Person deserializeXML(String xml) {
		XStream xs = new XStream();
		xs.alias("Person", Person.class);
		return (Person)xs.fromXML(xml);
	}
}

使用protobuf

1.快速入门

下载.exe编译器——编写.proto文件——利用编译器编译.proto文件生成javabean——引用jar包——直接使用javabean自带的序列化、反序列化方法

protobuf编译器官方下载地址:https://developers.google.com/protocol-buffers/docs/downloads

github下载地址:https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-win32.zip 

2.编写PersonBuilder.proto文件

syntax = "proto3";
option java_package = "test.protoc";
option java_outer_classname = "PersonBuilder"; 
message Person { 
	string name = 1;
	int32 age = 2;
}

syntax = "proto3";   我们使用proto3版协议

option java_package = "test.protoc"; 编译之后生成的Java文件的包名

option java_outer_classname = "PersonBuilder"; 编译之后生成的Java类的类名

message 相当于Java中的class

详细的介绍,请参考官方介绍

3.使用protoc编译上述.proto文件,生成javabean类

把.proto文件放在.exe同个目录下面,打开cmd,进入同目录下,执行命令:

protoc.exe --java_out=./ PersonBuilder.proto

假如.proto文件没有编写错误的话,成功后在同目录下即有javabean的类生成。

4.引用jar包

<!-- protobuf -->
<dependency>
	<groupId>com.google.protobuf</groupId>
	<artifactId>protobuf-java</artifactId>
	<version>3.5.1</version>
</dependency>

5.把刚刚生成的javabean复制到项目中,这里直接使用javabean自带的序列化、反序列化方法

package test;

import com.google.protobuf.InvalidProtocolBufferException;

import test.protoc.PersonBuilder;
import test.protoc.PersonBuilder.Person.Builder;

public class Test {
	public static void main(String[] args) throws InvalidProtocolBufferException {
		Person person = new Person();
		person.setName("张三");
		person.setAge(100);
		byte[] bytes = serializeProtoBuf(person);
		System.out.println("----------序列化---------");
		System.out.println(bytes);
		System.out.println("----------反序列化---------");
		System.out.println(deserializeProtoBuf(bytes));
	}
	public static byte[] serializeProtoBuf(Person person) {
		Builder builder = PersonBuilder.Person.newBuilder();
		builder.setName(person.getName());
		builder.setAge(person.getAge());
		return builder.build().toByteArray();
	}
	public static Person deserializeProtoBuf(byte[] bytes) throws InvalidProtocolBufferException {
		PersonBuilder.Person builder =  PersonBuilder.Person.parseFrom(bytes);
		Person person = new Person();
		person.setName(builder.getName());
		person.setAge(builder.getAge());
		return person;
	}
}

使用protostuff

1.引用jar包

<!-- protostuff -->
<dependency>
	<groupId>com.dyuproject.protostuff</groupId>
	<artifactId>protostuff-core</artifactId>
	<version>1.1.3</version>
	<optional>true</optional>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>com.dyuproject.protostuff</groupId>
	<artifactId>protostuff-runtime</artifactId>
	<version>1.1.3</version>
	<optional>true</optional>
	<scope>provided</scope>
</dependency>

2.序列化&反序列化

package test;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.google.protobuf.InvalidProtocolBufferException;

public class Test {
	public static void main(String[] args) throws InvalidProtocolBufferException {
		Person person = new Person();
		person.setName("张三");
		person.setAge(100);
		byte[] bytes = serializeProtoStuff(person);
		System.out.println("----------序列化---------");
		System.out.println(bytes);
		System.out.println("----------反序列化---------");
		System.out.println(deserializeProtoStuff(bytes));
	}
	public static byte[] serializeProtoStuff(Person person) {
		Schema<Person> schema = RuntimeSchema.getSchema(Person.class);
		LinkedBuffer buffer = LinkedBuffer.allocate(4096);
		return ProtostuffIOUtil.toByteArray(person, schema, buffer);
	}
	public static Person deserializeProtoStuff(byte[] bytes) {
		Schema<Person> schema = RuntimeSchema.getSchema(Person.class);
		Person person = new Person();
		ProtostuffIOUtil.mergeFrom(bytes, person, schema);
		return person;
	}
}

附件

protoc-3.1.0-win32.zip

打赏

您看完此文章的心情是

  • 0人

  • 鼓掌

    0人

  • 草泥马

    0人

  • 愤怒

    0人

  • 鄙视

    0人

评论

    暂无评论...