(六)分布式通信----MessagePack序列化
==>>点击查看本系列文章目录
1. .Net Core的序列化方式
1.1 json.Net
常用的工具包,如Newtonsoft.Json, 它是基于json格式的序列化和反序列化的组件
json.net 有以下优点:
侵入性:可以不添加attribute,就能进行序列化操作
灵活性:可以灵活性配置,比如允许被序列化的成员自定义名字,屏蔽的非序列化属性成员
可读性: 数据格式比较简单, 易于读写
依赖性:可以序列化成JObject,无需依赖对象进行序列化和泛型化。
1.2 protobuf
它是基于二进制格式的序列化和反序列化的组件
protobuf 有以下优点:
性能高 : 序列化后体积相比Json和XML很小,适合RPC二进制传输
跨语言:支持跨平台多语言
兼容性:消息格式升级和兼容性还不错
速度快 :序列化反序列化速度很快,快于Json的处理速度
1.3 messagepack
它是基于二进制格式的序列化和反序列化的组件
messagepack有以下优点:
性能高:序列化后体积相比Json和XML很小,适合RPC二进制传输
跨语言:支持跨平台多语言
兼容性:消息格式升级和兼容性还不错
速度快 :序列化反序列化速度很快,快于Json的处理速度
messagepack不管是小数据量还是大数据量都保持比较稳定的性能,本文中使用messagepack序列化方式。
2. 项目编码及设计模式
如下是文件结构:
2.1 工厂模式
抽象接口 工厂负责创建编码器和解码器
1.工厂
/// <summary> /// 一个抽象的传输消息编解码器工厂。 /// </summary> public interface ITransportMessageCodecFactory { /// <summary> /// 获取编码器。 /// </summary> /// <returns>编码器实例。</returns> ITransportMessageEncoder GetEncoder(); /// <summary> /// 获取解码器。 /// </summary> /// <returns>解码器实例。</returns> ITransportMessageDecoder GetDecoder(); }
2.编码器
/// <summary> /// 编码器 /// </summary> public interface ITransportMessageEncoder { byte[] Encode(TransportMessage message); }
3.解码器
/// <summary> /// 解码器 /// </summary> public interface ITransportMessageDecoder { TransportMessage Decode(byte[] data); }
实现类 工厂、编码器、解码器为MessagePack的实现
1.工厂
public sealed class MessagePackTransportMessageCodecFactory : ITransportMessageCodecFactory { #region Field private readonly ITransportMessageEncoder _transportMessageEncoder = new MessagePackTransportMessageEncoder(); private readonly ITransportMessageDecoder _transportMessageDecoder = new MessagePackTransportMessageDecoder(); #endregion Field #region Implementation of ITransportMessageCodecFactory /// <inheritdoc /> /// <summary> /// 获取编码器 /// </summary> /// <returns></returns> public ITransportMessageEncoder GetEncoder() { return _transportMessageEncoder; } /// <inheritdoc /> /// <summary> /// 获取解码器 /// </summary> /// <returns></returns> public ITransportMessageDecoder GetDecoder() { return _transportMessageDecoder; } #endregion Implementation of ITransportMessageCodecFactory }
2.编码器
public sealed class MessagePackTransportMessageEncoder : ITransportMessageEncoder { #region Implementation of ITransportMessageEncoder public byte[] Encode(TransportMessage transportMessage) { MessagePackTransportMessage messagePackTransportMessage = new MessagePackTransportMessage(transportMessage); return MessagePackSerializer.Serialize(messagePackTransportMessage); } #endregion Implementation of ITransportMessageEncoder }
3.解码器
public sealed class MessagePackTransportMessageDecoder : ITransportMessageDecoder { #region Implementation of ITransportMessageDecoder public TransportMessage Decode(byte[] data) { MessagePackTransportMessage messagePackTransportMessage = MessagePackSerializer.Deserialize<MessagePackTransportMessage>(data); return messagePackTransportMessage.GetTransportMessage(); } #endregion Implementation of ITransportMessageDecoder }
2.2 装饰器模式
高层的消息模型:
public class TransportMessage { /// <summary> /// 消息Id。 /// </summary> public string Id { get; set; } /// <summary> /// 消息内容。 /// </summary> public object Content { get; set; } /// <summary> /// 内容类型。 /// </summary> public string ContentType { get; set; } }
由于MessagePack序列化方式具有侵入性,需要添加 MessagePackObjectAttribute 和 KeyAttribute 特性,因此需要对 TransportMessage 做装饰:
using MessagePack; [MessagePackObject] public class MessagePackTransportMessage { private TransportMessage _transportMessage; public MessagePackTransportMessage(): this(new TransportMessage()) { } public MessagePackTransportMessage(TransportMessage transportMessage) { this._transportMessage = transportMessage; } public TransportMessage GetTransportMessage() { return _transportMessage; } /// <summary> /// 消息Id。 /// </summary> [Key(0)] public string Id { get { return _transportMessage.Id; } set { _transportMessage.Id = value; } } /// <summary> /// 消息内容。 /// </summary> [Key(1)] public object Content { get { return _transportMessage.Content; } set { _transportMessage.Content = value; } } /// <summary> /// 内容类型。 /// </summary> [Key(2)] public string ContentType { get { return _transportMessage.ContentType; } set { _transportMessage.ContentType = value; } } }
2.3 依赖注入
Autofac 是一个依赖注入工具包,比.net Core 原始的依赖注入拥有更完善的功能,中文官方文档:https://autofaccn.readthedocs.io/zh/latest/index.html
using Autofac; public static class ContainerBuilderExtensions { /// <summary> /// 使用messagepack编码解码方式 /// </summary> /// <param name="builder"></param> /// <returns></returns> public static ContainerBuilder UseMessagePackCodec(this ContainerBuilder builder) { builder.RegisterType(typeof(MessagePackTransportMessageCodecFactory)).As(typeof(ITransportMessageCodecFactory)).SingleInstance(); return builder; } }
2.4 单元测试
端到端的测试,同时测试编码和解码
using MessagePack; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] public class MessagePackTest { [TestMethod] public void TestCodec() { Person person = new Person { Name = "张宏伟", Age = 18 }; TransportMessage transportMessage = new TransportMessage { Id = "1", ContentType = "Person", Content = person }; MessagePackTransportMessageCodecFactory factory = new MessagePackTransportMessageCodecFactory(); ITransportMessageEncoder encoder = factory.GetEncoder(); ITransportMessageDecoder decoder = factory.GetDecoder(); byte[] vs = encoder.Encode(transportMessage); TransportMessage message =decoder.Decode(vs); Assert.AreEqual(message.Id, "1"); Assert.AreEqual(message.ContentType, "Person"); Assert.AreEqual(((object[])message.Content)[0].ToString(), "张宏伟" ); Assert.AreEqual(((object[])message.Content)[1].ToString(), "18"); } [MessagePackObject] public class Person { [Key(0)] public string Name { get; set; } [Key(1)] public int Age { get; set; } } }
作者:张宏伟同学
声明:原创博客请在转载时保留原文链接或者在文章开头加上本人博客地址,如发现错误或有疑问,欢迎指正提出。凡是转载于本人的文章,不能设置打赏功能,如有特殊需求请与本人联系!