最近在学习RPC相关的知识,既然是远程过程调用,就会涉及到在网络上传输的问题,发现常见的RPC框架并没有使用java原生的序列化机制。这里就来记录一下Java序列话的缺点。
一、Java序列序列化的缺点
缺点一:无法跨语言
这是一个比较致命的问题,当服务提供者或者调用这使用其他语言开发时,需要和相应的java进程进行交互时,由于java序列化后的字节数组,别的语言无法进行反序列化,这严重阻碍了它的应用。
缺点二:序列化后的码流太大
下面通过代码来证明java序列话之后,码流比较大
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String userName;
private int userID;
public UserInfo() {
}
public UserInfo(String userName, int userID) {
this.userName = userName;
this.userID = userID;
}
public UserInfo buildUserName(String userName) {
this.userName = userName;
return this;
}
public UserInfo buildUserID(int userID) {
this.userID = userID;
return this;
}
public final String getUserName() {
return userName;
}
public final void setUserName(String userName) {
this.userName = userName;
}
public final int getUserID() {
return userID;
}
public final void setUserID(int userID) {
this.userID = userID;
}
// 对UserInfo进行编码,编码的结果为字节数组
public byte[] codeC() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
byte[] value = this.userName.getBytes();
buffer.putInt(value.length);
buffer.put(value);
buffer.putInt(this.userID);
buffer.flip();
value = null;
byte[] result = new byte[buffer.remaining()];
buffer.get(result);
return result;
}
}
测试Java序列化字节数组和使用codeC()方法后字节数组的大小比较
public static void main(String[] args) throws IOException {
UserInfo info = new UserInfo();
info.buildUserID(100).buildUserName("Welcome to Netty");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(info);
os.flush();
os.close();
byte[] b = bos.toByteArray();
System.out.println("the jdk serializable length is : " + b.length);
bos.close();
System.out.println("--------------------------------");
System.out.println("The byte array serializable length is : " + info.codeC().length);
}
输出结果 通过结果发现,差距还是比较大的。
缺点三:序列化性能太低
这里做个试验,利用java序列化和不使用java序列化的数组进行比较其性能。
不使用java序列化
// 对象序列化成字节数组
public byte[] code(ByteBuffer buffer) {
buffer.clear();
byte[] value = this.userName.getBytes();
buffer.putInt(value.length);
buffer.put(value);
buffer.putInt(this.userID);
buffer.flip();
value = null;
byte[] result = new byte[buffer.remaining()];
buffer.get(result);
return result;
}
进行测试
// 比较性能的差异
public static void testPerformance() throws IOException {
UserInfo info = new UserInfo();
info.buildUserID(100).buildUserName("Welcome to Netty");
int loop = 1000000;
ByteArrayOutputStream bos = null;
ObjectOutputStream os = null;
long startTime = System.currentTimeMillis();
for (int i = 0; i < loop; i++) {
bos = new ByteArrayOutputStream();
os = new ObjectOutputStream(bos);
os.writeObject(info);
os.flush();
os.close();
byte[] b = bos.toByteArray();
bos.close();
}
long endTime = System.currentTimeMillis();
System.out.println("The jdk serializable cost time is : " + (endTime - startTime) + "ms");
System.out.println("--------------------------------");
ByteBuffer buffer = ByteBuffer.allocate(1034);
startTime = System.currentTimeMillis();
for (int i = 0; i < loop; i++ ) {
byte[] b = info.code(buffer);
}
endTime = System.currentTimeMillis();
System.out.println("The byte array serializable cost time is : " + (endTime - startTime) + " ms");
}
输出结果:可以发现java序列话的性能比较差
可以看出,无论是序列话后的码流大小,还是序列化的性能,JDK默认的序列化机制都表现的很差。因此,通常一般不会选择java序列化作为RPC框架的编解码机制。通常选用的序列化框架有:谷歌的 protobuf、Facebook的Thrift等等。