1. 程式人生 > >Netty學習8-自定義複雜序列化框架

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