Netty學習8-自定義複雜序列化框架
1 概述
《Netty學習7-序列化原理》一文中講述了序列化的原理,通過Java位運算、JDK原生的NIO、Netty的ChannelBuffer做了序列化操作。本文演示稍微複雜的一個自定義序列化框架,但萬變不離其宗,拆解出來還是很簡單的。
2 工具類
這是核心類。拆解來看就是呼叫了ChannelBuffer的readInt和writeInt等方法,並定義了抽象類方法read和write等待實體類實現。
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; /** * Buffer工具類 */ public class BufferUtils { /** * 獲取一個快取物件 * * @return 快取物件 */ public static ChannelBuffer getBuffer() { ChannelBuffer dynamicBuffer = ChannelBuffers.dynamicBuffer(); return dynamicBuffer; } /** * 將二進位制bytes寫入快取物件 * * @param bytes 二進位制資料 * @return 快取物件 */ public static ChannelBuffer getBuffer(byte[] bytes) { ChannelBuffer copiedBuffer = ChannelBuffers.copiedBuffer(bytes); return copiedBuffer; } } import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.jboss.netty.buffer.ChannelBuffer; import com.cn.core.BufferFactory; /** * 自定義序列化基類 */ public abstract class Serializer { // 編碼物件 public static final Charset CHARSET = Charset.forName("UTF-8"); // 寫快取 protected ChannelBuffer writeBuf; // 讀快取 protected ChannelBuffer readBuf; // 反序列化具體實現 protected abstract void read(); // 序列化具體實現 protected abstract void write(); /***************************************** 序列化 ************************************/ // 序列化 public byte[] serialze() { // 申明寫快取 writeBuf = BufferUtils.getBuffer(); // 將資料寫入寫快取 write(); // 將寫快取資料讀入byte陣列 byte[] bytes = null; if (writeBuf.writerIndex() == 0) bytes = new byte[0]; else { bytes = new byte[writeBuf.writerIndex()]; writeBuf.readBytes(bytes); } writeBuf.clear(); return bytes; } public Serializer writeShort(Short value) { writeBuf.writeShort(value); return this; } public Serializer writeInt(Integer value) { writeBuf.writeInt(value); return this; } public Serializer writeLong(Long value) { writeBuf.writeLong(value); return this; } public Serializer writeString(String value) { if (value == null || value.isEmpty()) { writeShort((short) 0); return this; } byte data[] = value.getBytes(CHARSET); short len = (short) data.length; writeBuf.writeShort(len); writeBuf.writeBytes(data); return this; } public Serializer writeByte(Byte value) { writeBuf.writeByte(value); return this; } public <T> Serializer writeList(List<T> list) { if (isEmpty(list)) { writeBuf.writeShort((short) 0); return this; } writeBuf.writeShort((short) list.size()); for (T item : list) { writeObject(item); } return this; } public <K, V> Serializer writeMap(Map<K, V> map) { if (isEmpty(map)) { writeBuf.writeShort((short) 0); return this; } writeBuf.writeShort((short) map.size()); for (Entry<K, V> entry : map.entrySet()) { writeObject(entry.getKey()); writeObject(entry.getValue()); } return this; } public Serializer writeObject(Object object) { if (object == null) { writeByte((byte) 0); } else { if (object instanceof Integer) { writeInt((int) object); return this; } if (object instanceof Long) { writeLong((long) object); return this; } if (object instanceof Short) { writeShort((short) object); return this; } if (object instanceof Byte) { writeByte((byte) object); return this; } if (object instanceof String) { String value = (String) object; writeString(value); return this; } if (object instanceof Serializer) { writeByte((byte) 1); Serializer value = (Serializer) object; value.writeToTargetBuffer(writeBuf); return this; } throw new RuntimeException("不可序列化的型別:" + object.getClass()); } return this; } // 呼叫物件自身的寫入方法 public ChannelBuffer writeToTargetBuffer(ChannelBuffer buffer) { writeBuf = buffer; write(); return writeBuf; } /***************************************** 反序列化 ************************************/ public Serializer deserialize(byte[] bytes) { readBuf = BufferUtils.getBuffer(bytes); read(); readBuf.clear(); return this; } public byte readByte() { return readBuf.readByte(); } public short readShort() { return readBuf.readShort(); } public int readInt() { return readBuf.readInt(); } public long readLong() { return readBuf.readLong(); } public String readString() { int size = readBuf.readShort(); if (size <= 0) { return ""; } byte[] bytes = new byte[size]; readBuf.readBytes(bytes); return new String(bytes, CHARSET); } public <T> List<T> readList(Class<T> clz) { List<T> list = new ArrayList<>(); int size = readBuf.readShort(); for (int i = 0; i < size; i++) { list.add(read(clz)); } return list; } public <K, V> Map<K, V> readMap(Class<K> keyClz, Class<V> valueClz) { Map<K, V> map = new HashMap<>(); int size = readBuf.readShort(); for (int i = 0; i < size; i++) { K key = read(keyClz); V value = read(valueClz); map.put(key, value); } return map; } @SuppressWarnings("unchecked") public <I> I read(Class<I> clz) { Object t = null; if (clz == int.class || clz == Integer.class) { t = this.readInt(); } else if (clz == byte.class || clz == Byte.class) { t = this.readByte(); } else if (clz == short.class || clz == Short.class) { t = this.readShort(); } else if (clz == long.class || clz == Long.class) { t = this.readLong(); } else if (clz == String.class) { t = readString(); } else if (Serializer.class.isAssignableFrom(clz)) { try { byte hasObject = this.readBuf.readByte(); if (hasObject == 1) { Serializer temp = (Serializer) clz.newInstance(); temp.readFromBuffer(this.readBuf); t = temp; } else { t = null; } } catch (Exception e) { e.printStackTrace(); } } else { throw new RuntimeException(String.format("不支援型別:[%s]", clz)); } return (I) t; } // 呼叫物件自身的讀取方法 public void readFromBuffer(ChannelBuffer readBuffer) { this.readBuf = readBuffer; read(); } /***************************************** 工具方法 ************************************/ private <T> boolean isEmpty(Collection<T> c) { return c == null || c.size() == 0; } public <K, V> boolean isEmpty(Map<K, V> c) { return c == null || c.size() == 0; } }
3 實體類
public class Hobby extends Serializer { private String name; public Hobby() { } @Override protected void read() { this.name = readString(); } @Override protected void write() { writeString(name); } public Hobby(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Hobby [name=" + name + "]"; } } public class Student extends Serializer { // 學號 private Integer id; // 姓名 private String name; // 分數 private Long mark; // 同學名 private List<String> classmates; // 愛好 private List<Hobby> hobbies; // 住址 private Map<String, String> address; @Override protected void write() { writeInt(id); writeString(name); writeLong(mark); writeList(classmates); writeList(hobbies); writeMap(address); } @Override protected void read() { this.id = readInt(); this.name = readString(); this.mark = readLong(); this.classmates = readList(String.class); this.hobbies = readList(Hobby.class); this.address = readMap(String.class, String.class); } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Long getMark() { return mark; } public void setMark(Long mark) { this.mark = mark; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getClassmates() { return classmates; } public void setClassmates(List<String> classmates) { this.classmates = classmates; } public List<Hobby> getHobbies() { return hobbies; } public void setHobbies(List<Hobby> hobbies) { this.hobbies = hobbies; } public Map<String, String> getAddress() { return address; } public void setAddresses(Map<String, String> address) { this.address = address; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", mark=" + mark + ", classmates=" + classmates + ", hobbies=" + hobbies + ", address=" + address + "]"; } }
4 測試方法
public class XYTest { public static void main(String[] args) { // 資料初始化 Student student = new Student(); student.setId(10); student.setName("xy"); student.setMark(100L); List<String> classmates = new ArrayList<String>(); classmates.add("xiaoming"); classmates.add("xiaohong"); student.setClassmates(classmates); List<Hobby> hobbies = new ArrayList<Hobby>(); hobbies.add(new Hobby("football")); student.setHobbies(hobbies); Map<String, String> address = new HashMap<String, String>(); address.put("aaa", "bbb"); address.put("ccc", "ddd"); student.setAddresses(address); // 序列化 byte[] array = student.serialze(); System.out.println(Arrays.toString(array)); // 反序列化 Student s = new Student(); s.deserialize(array); System.out.println(s.toString()); } }
相關推薦
Netty學習8-自定義複雜序列化框架
1 概述 《Netty學習7-序列化原理》一文中講述了序列化的原理,通過Java位運算、JDK原生的NIO、Netty的ChannelBuffer做了序列化操作。本文演示稍微複雜的一個自定義序列化框架,但萬變不離其宗,拆解出來還是很簡單的。 2 工具類 這是核心類。拆解來看
Netty學習(2): protobuf序列化框架學習
1. protobuf是什麼 protobuf是google旗下的產品,用於序列化與反序列化資料結構,但是比xml更小、更快、更簡單,而且能跨語言、跨平臺。你可以把你的資料按你的要求結構化,然後可以轉化成多種資料流,同時其他語言可以通過
自定義redis序列化工具
我們 utils 字節數 pac keys ted ive onu 問題 redis一個優點就是可以將數據寫入到磁盤中。 我們知道寫入磁盤的數據實際上都是以字節(0101這樣的二進制數據)的形式寫入的。 這意味著如果我們要將一個對象寫入磁盤,就必須將這個對象序列化。 jav
jackson中自定義處理序列化和反序列化
public turn ali fast col ast mar 繼承 con http://jackyrong.iteye.com/blog/2005323 ********************************************** 對於一直用gson的
圖片銜接自定義類序列化
#include <fstream> // include headers that implement a archivein simple text format #include<boost/archive/text_oarchive.hpp> #inclu
自定義Hadoop序列化been Demo
package hadoop.mapreduce.serializable; import org.apache.hadoop.io.Writable; import java.io.DataInput; import java.io.DataOutput; import
第七十五條 考慮使用自定義的序列化形式
序列化使用起來比價方便,但有一些常見的細節需要注意,比如說定義 serialVersionUID 值,關鍵字 transient 的用法,下面就用例子來說明 定義一個bean,實現序列化的介面, public class Student implements Serializable { &
QDataStream實現自定義物件序列化
專案需求將使用者上一次配置資訊儲存到硬碟上,以便下次使用者直接載入。我是講使用者配置資訊作為一個類存在的,研究了2天QT平臺上的物件序列化問題。C++的序列化問題在VC平臺上實現比較簡單。Java的序列化問題只需要實現
SpringBoot2.0 自定義Json序列化規則(忽略value為null的key序列化)
最近公司專案重構,發現介面返回的json資料中存在有value值為null 的key,這些應該被視為廢資料,不應該輸出給前端佔用頻寬,於是去修改json序列化的方式,在spring中我們都知道去xml配置檔案中加一行配置或者在輸出模型上加一@JsonInclud
考慮自定義的序列化模式(75)
一個類實現了Serializable 介面,並且使用了預設的序列化形式 無法擺脫該實現,永遠牽制該類的序列化形式 如
為Redis配置自定義fastJson序列化工具類
alibaba.fastjson內部已經提供了對Redis儲存物件序列化的工具類GenericFastJsonRedisS
jackson自定義全域性序列化、反序列化
需要自定義Jackson序列化和反序列化有兩種方式,一種是全域性定義,一種是非全域性定義。先來看看全域性定義。全域性定義的步驟如下
原始碼分析springboot自定義jackson序列化,預設null值個性化處理返回值
最近專案要實現一種需求,對於後端返回給前端的json格式的一種規範,不允許缺少欄位和欄位值都為null,所以琢磨了一下如何進行將springboot的Jackson序列化自定義一下,先看看如何實現,再去看原始碼 第一步:寫配置類 1 @Configuration 2 public class Web
記錄一次原始碼擴充套件案列——FastJson自定義反序列化ValueMutator
背景:曾經遇到一個很麻煩的事情,就是一個json串中有很多佔位符,需要替換成特定文案。如果將json轉換成物件後,在一個一個屬性去轉換的話就出出現很多冗餘程式碼,不美觀也不是很實用。 而且也不能提前在json串中替換,因為替換的文案會因為某些變數發生改變。就比如國際化,在中文的時候應該是"你好",而在英文的
《netty權威指南》之JBoss序列化框架Marshalling
前面講了netty解決拆包粘包的問題 我們發現拆包粘包問題的解決都只是解決netty傳送字串的情況 在企業及開發中很少有直接使用字串的,一般都有定義好的訊息體,這個訊息體一定對應實體類 如果要傳送實體類那麼久一定要對實體類做序列化 (序列化就是把檔案或者記憶體中的資料結構轉換
FastJson自定義複雜物件序列化
總結: SerializeFilter是通過程式設計擴充套件的方式定製序列化。fastjson支援6種SerializeFilter,用於不同場景的定製序列化。 PropertyPreFilter 根據PropertyName判斷是否序列化 Pr
netty使用msgpack自定義編解碼器實現序列化操作
匯入依賴 <dependency> <groupId>org.msgpack</groupId> <artifactId>msgpack</artifactId>
Netty 整合 MessagePack 序列化框架 + LengthFieldBasedFrameDecoder 自定義解碼器
環境準備及說明 如果是匯入二進位制開發包,則如下所示: 需要開發包的可以參考《 MessagePack 開發入門詳解》。 如果是 Maven 專案,則新增如下依賴: <!-- https://mvnrepository.com/artifact/
日常學習隨筆-自定義了一個MyArrayListDefin集合(數組擴容+叠代器+JDK1.8新方法+詳細說明)
fin array rgs def spl 三種 叠代 ldd ner 一、自定義了一個ArrayList的模擬集合(源碼+詳細說明) 前段時間分析了下ArrayList集合的源碼,總覺得如果不自己定義一個的話,好像缺了點什麽,所以有了如下的代碼。 代碼可以說是逐行註
Pytorch學習:自定義nn模組——一種搭建複雜網路的途徑
有時候順序化的模型並不能滿足我們搭建複雜網路的需求,這時候就可以使用子類nn.Module來定義一個向前傳播過程。 下面的例子中通過自定義模組定義了一個兩層的前向傳播模型: # -*- coding: utf-8 -*- import torch class Two