卖辅助网站怎么做的,上海比较有名的大公司有哪些,一级a做爰片免费网站破解版,wordpress 文章模板前言
Dubbo 框架采用 微内核 插件 的基本设计原则#xff0c;自身功能几乎也都通过 SPI 扩展点实现#xff0c;可以方便地被用户自由扩展和更换。 Dubbo 框架采用分层设计#xff0c;自上而下共分为十层#xff0c;各层均为单向依赖#xff0c;每一层都可以剥离上层被复…前言
Dubbo 框架采用 微内核 插件 的基本设计原则自身功能几乎也都通过 SPI 扩展点实现可以方便地被用户自由扩展和更换。 Dubbo 框架采用分层设计自上而下共分为十层各层均为单向依赖每一层都可以剥离上层被复用。 本篇文章就来介绍一下最底下的 Serialize 序列化层。
理解序列化
序列化 (Serialization) 是将对象的状态信息转换为可以存储或传输的字节序列的过程与之对应的还有反序列化即将可存储或传输的字节序列转换为对象的过程。
为什么需要序列化呢 以 Java 语言为例它是一门面向对象的编程语言我们在程序里操作的是对象方法调用的参数和返回值亦是对象。Dubbo 作为一个 RPC 框架基于代理帮我们实现了远程调用屏蔽了底层实现的细节。但是我们得知道对象本身是无法在网络中传输的网络传输的只能是字节序列。 所以Dubbo 在发送请求前先得把对象序列化成字节序列对端收到字节序列后再按照同样的规则反序列化成对象再交给我们的业务代码处理发送响应结果同样如此。
设计实现
Dubbo 针对 Serialize 层专门新建了一个dubbo-serialization 模块其中子模块dubbo-serialization-api 用于定义抽象接口其它模块负责具体实现。
dubbo-serialization
--dubbo-serialization-api
--dubbo-serialization-hessian2
--dubbo-serialization-fastjson
--dubbo-serialization-kryo
--dubbo-serialization-fst
--dubbo-serialization-jdk
--dubbo-serialization-protostuff
--dubbo-serialization-avro
......Serialize 层核心接口就三个
Serialization序列化接口用于生成序列化器和反序列化器ObjectOutput对象序列化器接口ObjectInput对象反序列化器接口
Serialization 是扩展接口用于生成具体的序列化器和反序列化器默认使用 hessian2。
SPI(hessian2)
public interface Serialization {byte getContentTypeId();String getContentType();AdaptiveObjectOutput serialize(URL url, OutputStream output) throws IOException;AdaptiveObjectInput deserialize(URL url, InputStream input) throws IOException;
}ObjectOutput 是序列化器的抽象接口用于往输出流写对象。它继承自 DataOutput除了可以写 Object还支持写 Java 基本类型和字节数组。
public interface ObjectOutput extends DataOutput {void writeObject(Object obj) throws IOException;/****下面是Dubbo协议特有的需求用来写异常、事件、和Map其它协议未必支持****/default void writeThrowable(Object obj) throws IOException {writeObject(obj);}default void writeEvent(Object data) throws IOException {writeObject(data);}default void writeAttachments(MapString, Object attachments) throws IOException {writeObject(attachments);}
}ObjectInput 是反序列化器的抽象接口用于从输入流读对象代码就不贴了。
看到这里你可能会有一个疑问。 RPC 请求和响应都被封装成 Request、Response 对象了为什么不只定义一个writeObject和readObject 方法直接读写整个 Request/Response 对象呢为什么还要单独提供读写 int、boolean、String 等基本类型的方法 这是因为Dubbo 协议的报文包含两部分协议头部、请求体。序列化只管请求体部分的数据对于协议头部它是不关心的。而 Request/Response 对象属性是同时包含这两部分的数据的如果直接序列化整个对象传输会造成带宽的浪费传输冗余的数据。 所以 Dubbo 的编解码器DubboCodec 不是一股脑直接读写整个大对象的而是按照顺序写多个对象对端再按照相同的顺序读出来就好了。
Dubbo 对 Request 编码的方法是DubboCodec#encodeRequestData 对于一次 Dubbo 协议的 RPC 调用Consumer 要依次写入
versionStringDubbo协议的版本号serviceNameString服务名versionString服务的版本号methodNameString方法名parameterTypesDescString参数类型描述argsObject…方法参数attachmentsMap隐式参数
Override
protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {RpcInvocation inv (RpcInvocation) data;out.writeUTF(version);// https://github.com/apache/dubbo/issues/6138String serviceName inv.getAttachment(INTERFACE_KEY);if (serviceName null) {serviceName inv.getAttachment(PATH_KEY);}out.writeUTF(serviceName);out.writeUTF(inv.getAttachment(VERSION_KEY));out.writeUTF(inv.getMethodName());out.writeUTF(inv.getParameterTypesDesc());Object[] args inv.getArguments();if (args ! null) {for (int i 0; i args.length; i) {out.writeObject(encodeInvocationArgument(channel, inv, i));}}out.writeAttachments(inv.getObjectAttachments());
}Provider 再从输入流里按照相同的顺序读出来即可代码是DecodeableRpcInvocation#decode 。
自定义序列化
Serialization 被设计成 SPI 接口所以它可以很轻松的被替换。 接下来我们就基于 Fastjson2 写一个序列化模块替换掉默认的 hessian2让你对整个序列化过程理解的更加清楚。
首先我们新建一个dubbo-extension-serialization-fastjson2 模块。因为我们要依赖 Dubbo 提供的接口去实现一套新的序列化组件所以自然要引入dubbo-serialization-api 模块。又因为我们是基于 fastjson2 实现的所以也得引入 fastjson2 的依赖。
dependenciesdependencygroupIdorg.apache.dubbo/groupIdartifactIddubbo-serialization-api/artifactIdversion${dubbo.version}/version/dependencydependencygroupIdcom.alibaba.fastjson2/groupIdartifactIdfastjson2/artifactIdversion2.0.44/version/dependency
/dependencies新建 Fastjson2Serialization 类实现 Serialization 接口很简单返回我们实现的 Fastjson2 对应的序列化器即可。
public class Fastjson2Serialization implements Serialization {Overridepublic byte getContentTypeId() {return 22;}Overridepublic String getContentType() {return text/json;}Overridepublic ObjectOutput serialize(URL url, OutputStream output) throws IOException {return new Fastjson2ObjectOutput(output);}Overridepublic ObjectInput deserialize(URL url, InputStream input) throws IOException {return new Fastjson2ObjectInput(input);}
}再编写 Fastjson2ObjectOutput 实现 ObjectOutput 接口实现序列化相关的逻辑。我们这里直接用 JSONB 格式传输效率比 JSON 字符串更高。
public class Fastjson2ObjectOutput implements ObjectOutput {private final OutputStream output;public Fastjson2ObjectOutput(OutputStream output) {this.output output;}Overridepublic void writeObject(Object obj) throws IOException {JSONWriter jsonWriter JSONWriter.ofJSONB();jsonWriter.writeAny(obj);jsonWriter.flushTo(output);}......省略一堆方法
}序列化器有了再就是 Fastjson2ObjectInput 反序列化器了同样的基于 JSONReader 读即可。
public class Fastjson2ObjectInput implements ObjectInput {private final InputStream input;private final JSONReader jsonReader;public Fastjson2ObjectInput(InputStream input) {this.input input;try {byte[] bytes new byte[input.available()];input.read(bytes);this.jsonReader JSONReader.ofJSONB(bytes);} catch (IOException e) {throw new RuntimeException(e);}}Overridepublic Object readObject() throws IOException, ClassNotFoundException {return jsonReader.readAny();}......省略一堆方法
}至此我们自定义的基于 Fastjson2 的序列化器就实现好了。
我们可以写个单元测试看看它是否可以正常工作
Test
public void test() throws Exception {Fastjson2Serialization serialization new Fastjson2Serialization();ByteArrayOutputStream outputStream new ByteArrayOutputStream();ObjectOutput objectOutput serialization.serialize(null, outputStream);objectOutput.writeUTF(xixi);objectOutput.writeInt(100);objectOutput.writeFloat(200.5F);objectOutput.flushBuffer();InputStream inputStream new ByteArrayInputStream(outputStream.toByteArray());ObjectInput objectInput serialization.deserialize(null, inputStream);Assertions.assertEquals(xixi, objectInput.readUTF());Assertions.assertEquals(100, objectInput.readInt());Assertions.assertEquals(200.5F, objectInput.readFloat());
}接下来的问题是如何让 Dubbo 加载我们自己写的序列化器呢 这就要利用到 Dubbo 的 SPI 机制了Dubbo 启动时会扫描 ClassPath 下所有的META-INF/dubbo 目录下以类的全限定名命名的文件然后读取文件内容以 Key-Value 的形式加载扩展接口的实现类。
所以我们也在模块里新建META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization 文件内容写上
fastjson2dubbo.extension.serialization.fastjson2.Fastjson2Serialization这样 Dubbo 就会去加载我们的序列化实现了。
最后一步就是让 Provider 和 Consumer 用上我们自定义的序列化器。Provider 可以在 ProtocolConfig 里指定
ProtocolConfig protocolConfig new ProtocolConfig(dubbo, 20880);
protocolConfig.setSerialization(fastjson2);ServiceConfig.setProtocol(protocolConfig);Consumer 可以在 ReferenceConfig 里设置参数来指定
MapString, String parameters new HashMap();
parameters.put(serialization, fastjson2);ReferenceConfig.setParameters(parameters);接下来你就可以启动 Provider 和 Consumer发起一次 RPC 调用看看是否用的你自定义的序列化器。
尾巴
Dubbo 框架设计自上而下分了十层最底层就是序列化层它提供了 Java 对象到字节序列互相转换的能力以方便参数和返回值可以在网络中传输。核心是利用 Serialization 接口用来生成序列化器和反序列化器Dubbo 官方内置了很多序列化实现开发者也可以自己实现一个实例化器再基于 SPI 机制方便的替换掉默认实现。