Netty學習7-序列化原理
阿新 • • 發佈:2019-02-10
1 概述
序列化:把Java物件轉化為byte陣列的過程。便於網路傳輸,儲存等。反序列化:把byte流還原為Java物件的過程。現有很多成熟的序列化框架如JDK原生序列化框架、google的protobuf等。本文來探究一下序列化的原理。
2 自定義序列化框架
現在需要轉化的是一個int物件,由4個位元組構成。那麼序列化過程就是把int物件這4個位元組,按照某種順序,分別寫到位元組陣列。本示例採取的是大端序列化方式,相關概念請參看本部落格的《大小端模式》和《Java中的位運算》兩篇文章。
3 原生NIO序列化
NIO封裝了相關方法,可以非常優雅得通過putInt和getInt獲取值。不足之處在於ByteBuffer.allocate指定的位元組陣列長度是固定的。
4 Netty中的channelBuffer(ByteBuf)
netty3.X是channelBuffer
netty4.X是ByteBuf
序列化:把Java物件轉化為byte陣列的過程。便於網路傳輸,儲存等。反序列化:把byte流還原為Java物件的過程。現有很多成熟的序列化框架如JDK原生序列化框架、google的protobuf等。本文來探究一下序列化的原理。
2 自定義序列化框架
現在需要轉化的是一個int物件,由4個位元組構成。那麼序列化過程就是把int物件這4個位元組,按照某種順序,分別寫到位元組陣列。本示例採取的是大端序列化方式,相關概念請參看本部落格的《大小端模式》和《Java中的位運算》兩篇文章。
註釋非常清楚,主要是利用了位運算進行序列化操作。若有兩個物件同時序列化,參看下例:import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; public class Test0 { public static void main(String[] args) throws IOException { // 高->低 [00000000 00000000 00000000 00000100] int id = 8; // 序列化 byte[] array = serial(id); // 反序列化 deSerial(array); } // 序列化 public static byte[] serial(int id) throws IOException { ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); arrayOutputStream.write(int2bytes(id)); byte[] byteArray = arrayOutputStream.toByteArray(); System.out.println(Arrays.toString(byteArray)); return byteArray; } // 反序列化 public static void deSerial(byte[] byteArray) throws IOException { ByteArrayInputStream arrayInputStream = new ByteArrayInputStream( byteArray); byte[] idBytes = new byte[4]; arrayInputStream.read(idBytes); System.out.println("id:" + bytes2int(idBytes)); } // 大端位元組序列 public static byte[] int2bytes(int i) { // 先寫高位,再寫低位 // 高->低 [00000000 00000000 00000000 00000100] // 步驟1:把最高位移到最右邊,轉換為byte // 步驟2:把第二高位移到最右邊,轉為byte // 步驟3:把第三高位移到最右邊,轉為byte // 步驟4:把最後一位移到最右邊,轉為byte byte[] bytes = new byte[4]; // 8的右移結果[00000000 00000000 00000000 00000000] 轉byte值為[00000000] bytes[0] = (byte) (i >> 3 * 8); // 8的右移結果[00000000 00000000 00000000 00000000] 轉byte值為[00000000] bytes[1] = (byte) (i >> 2 * 8); // 8的右移結果[00000000 00000000 00000000 00000000] 轉byte值為[00000000] bytes[2] = (byte) (i >> 1 * 8); // 8的右移結果[00000000 00000000 00000000 00000100] 轉byte值為[00000100] bytes[3] = (byte) (i >> 0 * 8); return bytes; } // 大端位元組反序列 public static int bytes2int(byte[] bytes) { // [00000000]左移,轉為int結果為[00000000 00000000 00000000 00000000] int b0 = (int) (bytes[0] << 3 * 8); // [00000000]左移,轉為int結果為[00000000 00000000 00000000 00000000] int b1 = (int) (bytes[1] << 2 * 8); // [00000000]左移,轉為int結果為[00000000 00000000 00000000 00000000] int b2 = (int) (bytes[2] << 1 * 8); // [00000100]左移,轉為int結果為[00000000 00000000 00000000 00000100] int b3 = (int) (bytes[3] << 0 * 8); // 位或結果[00000000 00000000 00000000 00000100] return b0 | b1 | b2 | b3; } }
public class Test1 { public static void main(String[] args) throws IOException { // 測試資料 int id = 8; int age = 10; // 序列化 ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); arrayOutputStream.write(int2bytes(id)); arrayOutputStream.write(int2bytes(age)); byte[] byteArray = arrayOutputStream.toByteArray(); System.out.println(Arrays.toString(byteArray)); // 反序列化 ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(byteArray); // 讀取第一個4位元組 byte[] idBytes = new byte[4]; arrayInputStream.read(idBytes); System.out.println("id:" + bytes2int(idBytes)); // 讀取第二個4位元組 byte[] ageBytes = new byte[4]; arrayInputStream.read(ageBytes); System.out.println("age:" + bytes2int(ageBytes)); } }
3 原生NIO序列化
NIO封裝了相關方法,可以非常優雅得通過putInt和getInt獲取值。不足之處在於ByteBuffer.allocate指定的位元組陣列長度是固定的。
import java.nio.ByteBuffer; import java.util.Arrays; public class Test2 { public static void main(String[] args) { // 測試資料 int id = 8; int age = 10; // 序列化 ByteBuffer buffer = ByteBuffer.allocate(8); buffer.putInt(id); buffer.putInt(age); byte[] array = buffer.array(); System.out.println(Arrays.toString(buffer.array())); // 反序列化 ByteBuffer buffer2 = ByteBuffer.wrap(array); System.out.println("id:" + buffer2.getInt()); System.out.println("age:" + buffer2.getInt()); } }
4 Netty中的channelBuffer(ByteBuf)
netty3.X是channelBuffer
netty4.X是ByteBuf
import java.util.Arrays;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
public class Test3 {
public static void main(String[] args) {
// 長度可動態擴充套件
ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
buffer.writeInt(8);
buffer.writeInt(20);
// 序列化
byte[] bytes = new byte[buffer.writerIndex()];
// 從channelBuffer讀取至二進位制陣列
buffer.readBytes(bytes);
System.out.println(Arrays.toString(bytes));
// 反序列化
ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer(bytes);
System.out.println(wrappedBuffer.readInt());
System.out.println(wrappedBuffer.readInt());
}
}