前文中介绍了有关Dubbo协议的相关知识。Dubbo协议是Dubbo框架自定义的一种协议,类似于HTTP协议,也是一种应用层协议。
从Dubbo框架结构来看(参考:https://dubbo.apache.org/zh/docsv2.7/dev/design/),其位于如下位置:
服务消费者和提供者依据协议的模式来进行消息的发送和接收。
在消息发送的过程中,需要对消息体进行序列化 *** 作,而Dubbo本身提供了多种序列化方式,本文就来简单了解下这些序列化方式。
1.获取序列化方式的入口之前DubboCodec中我们有简单说明过,入口在以下位置:
public class ExchangeCodec extends TelnetCodec { // 发送数据之前进行编码 *** 作 public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException { if (msg instanceof Request) { // 关注点在这里 encodeRequest(channel, buffer, (Request) msg); } else if (msg instanceof Response) { encodeResponse(channel, buffer, (Response) msg); } else { super.encode(channel, buffer, msg); } } protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException { // 在这里获取序列化方式 Serialization serialization = getSerialization(channel); ... } protected Serialization getSerialization(Channel channel) { // 具体见1.1 return CodecSupport.getSerialization(channel.getUrl()); } }1.1 CodecSupport.getSerialization()
public class CodecSupport { public static Serialization getSerialization(URL url) { return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension( url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION)); } }
同样是通过SPI的方式来获取序列化方式。如果在url中没有配置的话,则默认是hessian2方式。
2.Dubbo的序列化方式通过Serialization接口的实现类,我们可以看到Dubbo支持的序列化方式如下:
以上是常用的几种序列化方式,至于这些序列化方式的使用场景,在 成熟度 | Apache Dubbo 中有说明
而如果是纯java应用,则可以考虑使用性能更高的Kryo/FST序列化方式,在官网有关于其性能测试结果,具体在 Kryo 和 FST 序列化 | Apache Dubbo
最终结果如下两张图:
由以上测试结果可以看到:Kryo/FST相对其他序列化方式有显著的改进。
3.序列化源码解析序列化的方式有这么多种,笔者不一一介绍了,挑一个大家都比较熟悉的,说明一下序列化的过程即可。
那我们就选择JavaSerialization(JDK原生的序列化方式)来做说明
3.1 序列化的过程首先我们从ExchangeCodec.java来看下序列化的过程,这样可以更针对性的学习序列化的相关实现
public class ExchangeCodec extends TelnetCodec { protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException { // 获取序列化实现方式 Serialization serialization = getSerialization(channel); ... // 通过serialize()方法获取ObjectOutput对象 ObjectOutput out = serialization.serialize(channel.getUrl(), bos); if (req.isEvent()) { encodeEventData(channel, out, req.getData()); } else { // 序列化请求data encodeRequestData(channel, out, req.getData(), req.getVersion()); } // 刷新缓存 out.flushBuffer(); ... } protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException { encodeRequestData(out, data); } protected void encodeRequestData(ObjectOutput out, Object data) throws IOException { // 最终通过调用ObjectOutput.writeObject()方法来实现序列化 out.writeObject(data); } }
通过分析可知:序列化的过程主要分为以下几个步骤:
* 获取序列化实现方式Serialization
* 通过Serialization.serialize() 方法获取ObjectOutput对象,后续都是通过ObjectOutput来 *** 作
* 通过ObjectOutput.writeObject() 实现对请求对象的序列化
* 刷新ObjectOutput
通过以上序列化过程,我们参照JavaSerialization来观察其实现。
3.2 JavaSerializationpublic class JavaSerialization implements Serialization { // Constants.java中定义 byte JAVA_SERIALIZATION_ID = 3; public byte getContentTypeId() { return JAVA_SERIALIZATION_ID; } @Override public String getContentType() { return "x-application/java"; } // 获取ObjectOutput对象 public ObjectOutput serialize(URL url, OutputStream out) throws IOException { return new JavaObjectOutput(out); } @Override public ObjectInput deserialize(URL url, InputStream is) throws IOException { return new JavaObjectInput(is); } }
JavaSerialization中所使用的ObjectOutput实现类为JavaObjectOutput,后续的序列化 *** 作都交由JavaObjectOutput来实现
3.2.1 JavaObjectOutput的使用
public class JavaObjectOutput extends NativeJavaObjectOutput { public JavaObjectOutput(OutputStream os) throws IOException { // 创建一个JDK原声的ObjectOutputStream对象,用于序列化对象 super(new ObjectOutputStream(os)); } public JavaObjectOutput(OutputStream os, boolean compact) throws IOException { super(compact ? new CompactedObjectOutputStream(os) : new ObjectOutputStream(os)); } @Override public void writeUTF(String v) throws IOException { if (v == null) { getObjectOutputStream().writeInt(-1); } else { getObjectOutputStream().writeInt(v.length()); getObjectOutputStream().writeUTF(v); } } // 主要看这个方法 public void writeObject(Object obj) throws IOException { if (obj == null) { getObjectOutputStream().writeByte(0); } else { // 本质上直接调用了ObjectOutputStream.writeObject()方法 getObjectOutputStream().writeByte(1); getObjectOutputStream().writeObject(obj); } } @Override public void flushBuffer() throws IOException { // 直接调用ObjectOutputStream.flush()进行刷新 getObjectOutputStream().flush(); } }总结:
JavaSerialization的实现并不算复杂,本质上,所有的序列化 *** 作都交由JDK原声的ObjectOutputStream来执行。
而其他的序列化方式也是类似的,通过Serialization提供一个标准模板,具体的序列化 *** 作都交由具体的实现来完成即可。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)