《Netty权威指南 第2版》学习笔记(4)---在网络传输中使用Java序列化存在的问题

前言

基于Java提供的对象输入、输出流ObjectInputStream和ObjectOutputStream,可以直接把Java对象作为可存储的字节数组写入文件,也可以传输到网络上,基于JDK默认的序列化机制可以避免操作底层的字节数组,从而提升开发效率。

Java序列化的缺点

Java序列化从JDK1.1版本就已经提供,它不需要添加额外的类库,只需实现java.io.Serializable并生成序列ID即可,因此,它从诞生之初就得到了广泛的应用。

但是在远程服务调用(RPC)时,很少直接使用Java系列化进行消息的编解码和传输,原因主要归为如下几点。

1、无法跨语言

对于跨进程的服务调用,服务提供者可能会使用 C++或者其他语言开发,当我们需要和异构语言进程交互时 Java 序列化就难以胜任。由于 Java 序列化技术是 Java 语言内部的私有协议,其他语言并不支持,对于用户来说它完全是黑盒。对于 Java 序列化后的字节数组,别的语言无法进行反序列化,这就严重阻碍了它的应用。

2、序列化后的码流太大

测试案例,对比Java序列化后的字节数组大小和使用ByteBuffer进行编码后的大小。


import java.io.Serializable;
import java.nio.ByteBuffer;

public class UserInfo implements Serializable {
    
    

    private String userName;

    private int age;

    public void setUserName(String userName) {
    
    
        this.userName = userName;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }
    
    public byte[] codeC() {
    
    
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        byte[] value = this.userName.getBytes();
        buffer.putInt(value.length);
        buffer.put(value);
        buffer.putInt(age);
        buffer.flip();
        byte[] result = new byte[buffer.remaining()];
        buffer.get(result);
        return result;
    }
}


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class TestUserInfo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("test netty Serializable");
        userInfo.setAge(18);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(userInfo);
        oos.flush();
        oos.close();
        byte[] b = bos.toByteArray();
        System.out.println("jdk Serializable length : " + b.length);
        bos.close();
        System.out.println("byte Serializable length : " + userInfo.codeC().length);
    }
}

在这里插入图片描述

差距显而易见,编码后的字节数组越大,存储的时候就越占空间,存储的硬件成本就越高,并且在网络传输时更占宽带,导致系统的吞吐量降低。

3、序列化性能太低

稍作修改

    public byte[] codeC(ByteBuffer buffer) {
    
    
        buffer.clear();
        byte[] value = this.userName.getBytes();
        buffer.putInt(value.length);
        buffer.put(value);
        buffer.putInt(age);
        buffer.flip();
        value = null;
        byte[] result = new byte[buffer.remaining()];
        buffer.get(result);
        return result;
    }
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;

public class TestUserInfo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("test netty Serializable");
        userInfo.setAge(18);
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        int loop = 1000000;
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
    
    
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(userInfo);
            oos.flush();
            oos.close();
            byte[] b = bos.toByteArray();
            bos.close();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("jdk Serializable time : " + (endTime - startTime));


        ByteBuffer buffer = ByteBuffer.allocate(1024);
        startTime = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
    
    
            byte[] b = userInfo.codeC(buffer);
        }
        endTime = System.currentTimeMillis();
        System.out.println("byte Serializable time : " + (endTime - startTime));
    }
}

在这里插入图片描述

总结

从结果可以看出,无论是序列化后的码流大小,还是序列化的性能,JDK默认的序列化机制表现的都很差,因此,我们通常不会选择Java序列化作为远程跨节点调用的编解码框架。

猜你喜欢

转载自blog.csdn.net/CSDN_WYL2016/article/details/114117579