三种java对象跨语言序列化反序列化实现与效率对比-上

    java对象常用的跨语言序列化反序列化主要有三种:一是xml形式;二是json形式;三是protobuf字节流形式。本篇文章主要介绍这三种序列化反序列化方式的实现和其效率对比。

    首先介绍xml形式的序列化与反序列化,使用jaxb来实现。JAXB能够使用Jackson对JAXB注解的支持实现(jackson-module-jaxb-annotations),既方便生成XML,也方便生成JSON,这样一来可以更好的标志可以转换为JSON对象的JAVA类。JAXB允许JAVA人员将JAVA类映射为XML表示方式,常用的注解包括:@XmlRootElement,@XmlElement等等其maven依赖为:

<!-- http://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core -->
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.2.11</version>
</dependency>
<!-- http://mvnrepository.com/artifact/javax.xml/jaxb-api -->
<dependency>
    <groupId>javax.xml</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.1</version>
</dependency>
<!-- http://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.2.11</version>
</dependency>

定义的pojo类有两个:第一个是Book.java,另一个为BookList.java,是Book的集合类。只需要在定义的类名上添加@XmlRootElement注解即可,对业务代码没有侵入性。其中两个类中的属性值上有@Protobuf注解,这是protobuf序列化需要的,对xml序列化无影响。

Book类代码:

package zhangq.pojo;

import javax.xml.bind.annotation.XmlRootElement;

import com.baidu.bjf.remoting.protobuf.FieldType;
import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;

@XmlRootElement
public class Book {
	@Protobuf(fieldType = FieldType.INT32, order=1)
	int  id;
	
	@Protobuf(fieldType = FieldType.STRING, order=2)
	String name;
	
	@Protobuf(fieldType = FieldType.STRING, order=3)
	String address;
	
	@Protobuf(fieldType = FieldType.STRING, order=4)
	String buyer;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getBuyer() {
		return buyer;
	}

	public void setBuyer(String buyer) {
		this.buyer = buyer;
	}

	@Override
	public String toString() {
		return "Book [id=" + id + ", name=" + name + ", address=" + address + ", buyer=" + buyer + "]";
	}
	
	
	
}

BookList类代码:

package zhangq.pojo;

import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;

@XmlRootElement
public class BookList{
	
	@Protobuf(order=1)
	private List<Book> books;

	public List<Book> getBooks() {
		return books;
	}

	public void setBooks(List<Book> books) {
		this.books = books;
	}

	@Override
	public String toString() {
		return "BookList [books=" + books + "]";
	}
	
	
}

定义完pojo后,就可以进行xml的序列化与反序列化实现了。

首先定义一个测试辅助类,用来生成pojo实例:

package zhangq.test;

import java.util.ArrayList;
import java.util.List;

import zhangq.pojo.Book;
import zhangq.pojo.BookList;

public class TestHelper {
	public static BookList buildBookList(int count){
		BookList bookList = new BookList();
		List<Book> books = new ArrayList<Book>();
		for	(int i=0; i<count; i++){
			books.add(buildBook(i));
		}
		bookList.setBooks(books);
		return bookList;
	}
	
	public static Book buildBook(int id){
		Book book = new Book();
		book.setAddress("Peking");
		book.setBuyer("hello");
		book.setId(id);
		book.setName("Netty");
		return book;
	}
}

然后,定义一个性能记录类,用来记录序列化与反序列化的耗时:

package zhangq.util;

import org.apache.log4j.Logger;

public class PerformanceRecord {
	private static Logger m_Logger = Logger.getLogger(PerformanceRecord.class);
	
	private String desp;
	private long iStart;
	private PerformanceRecord(String desp){
		this.desp = desp;
	}
	
	public static PerformanceRecord getInstance(String desp){
		return new PerformanceRecord(desp);
	}
	
	public long start(){
		iStart = System.nanoTime();
		return iStart;
	}
	
	public double endInSeconds(){
		long iEnd = System.nanoTime();
		
		double timeInSeconds = (iEnd - iStart) / (1000000000.0);
		
		m_Logger.info(desp + " 耗时为 [" + timeInSeconds + "] 秒");
		return timeInSeconds;
	}
	
	public double endInMs(){
		long iEnd = System.nanoTime();
		
		double timeInMs = (iEnd - iStart) / (1000000.0);
		
		m_Logger.info(desp + " 耗时为 [" + timeInMs + "] 毫秒");
		return timeInMs;
	}
	
	public long endInNs(){
		long iEnd = System.nanoTime();
		
		long timeInNs = (iEnd - iStart);
		
		m_Logger.info(desp + " 耗时为 [" + timeInNs + "] 纳秒");
		return timeInNs;
	}
}

使用jaxb进行xml序列化的代码为:

	public static String  testMarshallList(int count) throws Exception{
		BookList books = TestHelper.buildBookList(count);
		JAXBContext jaxbContext = JAXBContext.newInstance(BookList.class);
		Marshaller marshaller = jaxbContext.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		OutputStream outputStream = new ByteArrayOutputStream();
		PerformanceRecord performanceRecord = PerformanceRecord.getInstance("XmlMashall");
		performanceRecord.start();
		marshaller.marshal(books, outputStream);
		performanceRecord.endInMs();
		String string = outputStream.toString();
		outputStream.close();
		//m_Logger.debug("ObjToXml:");
		//m_Logger.debug(string);
		return string;
	}

使用jaxb进行xml反序列化的代码为:

public static BookList testUnMarshallList(String string) throws Exception{
		JAXBContext jaxbContext = JAXBContext.newInstance(BookList.class);
		Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
		InputStream inputStream = new ByteArrayInputStream(string.getBytes());
		PerformanceRecord performanceRecord = PerformanceRecord.getInstance("XmlUnmashall");
		performanceRecord.start();
		BookList books = (BookList)unmarshaller.unmarshal(inputStream);
		performanceRecord.endInMs();
		//m_Logger.debug("XmlToObj:");
		//m_Logger.debug(books.toString());
		return books;
	}

    其次介绍json的序列化,使用jackson实现。使用jackson,不需要对pojo进行任何修改,不需要添加注解。其maven依赖为:

	<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
	<dependency>
	    <groupId>com.fasterxml.jackson.core</groupId>
	    <artifactId>jackson-core</artifactId>
	    <version>2.9.5</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
	<dependency>
	    <groupId>com.fasterxml.jackson.core</groupId>
	    <artifactId>jackson-databind</artifactId>
	    <version>2.9.5</version>
	</dependency>
	
	<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
	<dependency>
	    <groupId>com.fasterxml.jackson.core</groupId>
	    <artifactId>jackson-annotations</artifactId>
	    <version>2.9.5</version>
	</dependency>

jackson的json序列化代码为:

	public static String testObjToJsonList(int count) throws Exception{
		String string = null;
		
		BookList books = TestHelper.buildBookList(count);
		ObjectMapper mapper = new ObjectMapper(); 
		
		PerformanceRecord performanceRecord = PerformanceRecord.getInstance("Jsonmashall");
		performanceRecord.start();
		string = mapper.writeValueAsString(books);
		performanceRecord.endInMs();
//		m_Logger.debug("ObjToJson:");
//		m_Logger.debug(string);
		return string;
	}

jackson的json反序列化代码为:

	public static BookList testJsonToObjList(String string) throws Exception{
		BookList books = null;
		ObjectMapper mapper = new ObjectMapper();
		PerformanceRecord performanceRecord = PerformanceRecord.getInstance("JsonUnmashall");
		performanceRecord.start();
		books = mapper.readValue(string, BookList.class);
		performanceRecord.endInMs();
//		m_Logger.debug("JsonToObj:");
//		m_Logger.debug(books.toString());
		return books;
	}
    最后是protobuf字节流的序列化与反序列化,使用jprotobuf库进行,jprotobuf库的优点是使用简单,只需要在pojo上添加@protobuf注解即可,关于jprotobuf的介绍请看其git:https://github.com/jhunters/jprotobuf/ 。其maven依赖为:
<!-- https://mvnrepository.com/artifact/com.baidu/jprotobuf -->
	<dependency>
	    <groupId>com.baidu</groupId>
	    <artifactId>jprotobuf</artifactId>
	    <version>2.1.8</version>
	</dependency>
jprotobuf序列化代码为:
public static byte[] testObjToByteList(int count){
		Codec<BookList> simpleTypeCodec = ProtobufProxy
	            .create(BookList.class);
		BookList books = TestHelper.buildBookList(count);
		byte[] bytes = null;
		try {
			PerformanceRecord performanceRecord = PerformanceRecord.getInstance("ProtoBufMashall:");
			performanceRecord.start();
			
			bytes = simpleTypeCodec.encode(books);
			
			performanceRecord.endInMs();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			m_Logger.error(e.toString());
		}
		return bytes;
	}
jprotobuf反序列化代码为:
public static  BookList testByteToObjList(byte[] bytes){
		Codec<BookList> simpleTypeCodec = ProtobufProxy
	            .create(BookList.class);
		BookList books = null;
		try{
			PerformanceRecord performanceRecord = PerformanceRecord.getInstance("ProtoBufUnMashall:");
			performanceRecord.start();
			
			books = simpleTypeCodec.decode(bytes);
			performanceRecord.endInMs();
		}catch (Exception e){
			m_Logger.error(e.toString());
		}
		return books;
	}
    最后,需要对这三种方式的序列化与反序列化耗时进行记录,并对其序列化后的字节大小进行比较。需要注意的是,这三种方式都会涉及到预处理,并且内部有缓存等优化机制,因此对每种的序列化与反序列化函数运行两次,取第二次的耗时,这更符合实际工程运行时的耗时。
下面是序列化耗时:
其中横轴代表Book实例的个数,纵轴表示耗时,单位毫秒。

下面是反序列化耗时:

其中横轴代表Book实例的个数,纵轴表示耗时,单位毫秒。


下面是序列化后字节大小:
横轴是Book实例个数,纵轴是字节个数,单位个。

    根据图表分析,jprotobuf进行序列化时,耗时最长,但是反序列化耗时最短、序列化字节长度最短。xml/jaxb反序列化耗时最长,序列化字节长度最长。json/jackson表现较为适中。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值