protobuff-java 替代品 prorostuff
網路主題
傳送方需要將類物件轉換成二進位制壓入專案自定義資料結構,接收方接收到資料後,需要將二進位制轉換成類物件。
專案接收方通過訊息號和回執ID,可以知道該訊息如何去處理。
prorostuff相比.proto檔案,不用先轉換和編譯.proto檔案,不需要做一層中間檔案的轉換。這層中間檔案經常會和版本嚴格匹配時出現格式語法錯誤。
Pom如下:
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.4.0</version>
</dependency>
netty的編碼類
netty只用4是Java網路的一個主流方式
這裡需要通過繼承Netty4MessageToByteEncoder Message是Bean物件,根據自己專案定製來的
public class MessageEncoder extends MessageToByteEncoder<NettyMessage>{
@Override
protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf out) throws Exception {
//ProrostuffSerialize提供了序列化方式。
out.writeBytes(ProrostuffSerialize.serialize(msg));
}
}
關於對ProrostuffSerialize實現,本身還是建立有序快取空間,schema流式,提供正反序列化方式。
import com.dyuproject.protostuff.LinkedBuffer;
下面的ProtostuffIOUtil等都是這個包下面的。
public class ProrostuffSerialize{
private static class SerializeObject{
private Object target;
}
@SuppressWarnings("unchecked")
public static byte[] serialize(Object object) {
SerializeObject serializeObject = new SerializeObject();
serializeObject .target = object;
Class<serializeObject > serializeObjectClass = (Class<serializeObject >) serializeObject.getClass();
LinkedBuffer buffer= LinkedBuffer.allocate(1024 * 4);
try {
Schema<serializeObject > schema = RuntimeSchema.getSchema(serializeObjectClass );
return ProtostuffIOUtil.toByteArray(serializeObject , schema, buffer);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
linkedBuffer.clear();
}
}
//clazz泛型是Bean物件Message
@SuppressWarnings("unchecked")
public static <T> T deserialize(byte[] data, Class<T> clazz) {
try {
//建立SerializeObject的schema物件
Schema<SerializeObject> schema = RuntimeSchema.getSchema(SerializeObject.class);
SerializeObject serializeObject= schema.newMessage();
ProtostuffIOUtil.mergeFrom(data, serializeObject, schema);
return (T) serializeObject.target;
} catch (Exception e) {
log.error("not found schema obj");
throw new IllegalStateException(e.getMessage(), e);
}
}
public static <T> byte[] serializeList(List<T> objList) {
if (CollectionUtils.isEmpty(objList)) {
log.error("objList is empty");
throw new RuntimeException("Failed to serializer");
}
@SuppressWarnings("unchecked") Schema<T> schema =
(Schema<T>) RuntimeSchema.getSchema(objList.get(0).getClass());
LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
byte[] bytes = null;
ByteArrayOutputStream outputStream= null;
try {
outputStream= new ByteArrayOutputStream();
ProtostuffIOUtil.writeListTo(outputStream, objList, schema, buffer);
bytes = outputStream.toByteArray();
} catch (Exception e) {
log.error("Failed to serializer, objList={}", objList);
throw new RuntimeException("Failed to serializer");
} finally {
buffer.clear();
outputStream.close();
}
return bytes;
}
}
serialize時候,使用這個ProtobufIOUtil.toByteArray(T message, Schema schema, LinkedBuffer buffer)壓到不同資料型別,預設是byte[]
想變成字串在外面包一層new String(ProtobufIOUtil.toByteArray())就行。
上面的反序列化陣列就不寫了。
netty的解碼類
LengthFieldBasedFrameDecoder繼承自MessageToByteDecoder,也是使用netty對Message進行自行處理分流和處理分包。
public class MessageDecoder extends LengthFieldBasedFrameDecoder{
public MessageDecoder(int maxLength, int offset, int lengthFieldLength) {
super(maxLength, offset, lengthFieldLength);
}
@Override
public Object decode(ChannelHandlerContext ctx, ByteBuf input) throws Exception {
try {
//要使用readBytes防止會讀取不到,需要先給他申請可讀部分的空間,這塊是用隱式指標進行位移。
byte[] dstBytes = new byte[input.readableBytes()];
//讀取快取區接收到剩餘部分二進位制
input.readBytes(dstBytes,0,input.readableBytes());
//接收到Message物件
return SerializeUtil.deserialize(dstBytes, Message.class);
} catch (Exception e) {
log.error("exception when decoding: {}",e);
return null;
}
}
}
然後把編碼器和解碼器新增到nettyOptions管道容器的地方
@Component
public class ChannelInitializer extends ChannelInitializer<SocketChannel> {
//自定義Handler
@Autowired
ChannelHandler channelHandler;
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channel= socketChannel.pipeline();
channel.addLast("idleStateHandler",
new IdleStateHandler(5, 0, 0, TimeUnit.MINUTES));
//字串編解碼器
channel.addLast("encoder", new NettyMessageEncoder());
channel.addLast("decoder",new MessageDecoder(1024 * 1024, 4, 4));
pipeline.addLast("channelHandler", ChannelHandler);
}
}
施工中
相關文章
- [譯]JSX的替代品JS
- LastPass 的開源替代品AST
- Redux、rematch、dva的替代品:smoxReduxREM
- Turtl:Evernote 的開源替代品
- AppFlowy:Notion 的開源替代品APP
- Ubuntu 下 CCleaner 的 4 個替代品Ubuntu
- grpc-gateway的替代品--TurboRPCGateway
- CentOS已死:RedHat稱Stream不是替代品CentOSRedhat
- 命令列常用工具的替代品命令列
- 命令列基礎工具的更佳替代品命令列
- 交流負載箱是否有替代品出現?負載
- Joplin:真正的 Evernote 開源替代品
- PSRAM是非同步SRAM的理想替代品非同步
- windows 開發者神器 tc – total command和替代品Windows
- GTD 工具 Trello 的 5 個開源替代品
- 2024 Selenium10個替代品
- Figma 替代品 Penpot 安裝和使用教程
- 10 個 Linux 中最好的 Visio 替代品Linux
- Adobe 軟體的最佳 Linux 替代品Linux
- Lime:Sublime Text編輯器的開源替代品
- AvaloniaUI 中的 WPF CompositionTarget.Rendering 替代品UI
- Figma 替代品 Excalidraw 安裝和使用教程
- Adobe Photoshop 的 4 種自由開源替代品
- Adobe Lightroom 的三個開源替代品OOM
- 谷歌棄用 APK 格式!替代品 AAB 有何優勢?谷歌APK
- 注重隱私的安卓作業系統替代品:CalyxOS安卓作業系統
- Rocketgraph:用Golang編寫的Firebase的開源替代品Golang
- Rust編寫的Memcached快取替代品:memc.rsRust快取
- 多說的替代品——來必力評論系統
- TMPG ENC的開源替代品(內容由OpenAI 生成)OpenAI
- Deno 執行時入門教程:Node.js 的替代品Node.js
- HTM – JSX 的替代品?還是另一種選擇?JS
- HTM - JSX 的替代品?還是另一種選擇?JS
- Github被微軟收購,這裡整理了16個替代品Github微軟
- Digg官方宣佈開發Google Reader替代品Go
- WPS Office:Linux 上的 Microsoft Office 的免費替代品LinuxROS
- 那些 Unix 命令替代品們「GitHub 熱點速覽 v.21.32」Github
- Slack 的開源替代品 Mattermost 獲得 5000 萬美元融資