Dubbo 多协议
Dubbo 多协议
前言
大家好,今天开始给大家分享 — Dubbo 专题之 Dubbo 多协议。在前面的章节中我们介绍了 Dubbo 静态服务,了解了什么是静态服务以及静态服务使用场景和实现原理,同时我们知道了静态服务能够通过手动的形式上下线服务或者配置服务为只订阅和只注册模式。有的小伙伴可能看到有的案例中通过 HTTP 的形势调用 Dubbo 服务是不是感觉很疑惑呢?那么在这个章节中我们会介绍 Dubbo 多协议来揭开这个疑惑。那么什么是 Dubbo 的协议呢?Dubbo 支持哪些常用的协议呢?那就让我们快速开始吧!
1. Dubbo 的协议简介
首先有编程经验的小伙伴都知道所谓的协议其实就是规则,首先我们要沟通交流得指定规则才能正确、高效的进行。例如:在战争时期我们通过发送电报进行相互通讯传递信息,这里为了保证发送安全我们在发送电报时把一段信息按照一定的规则进行处理然后发送出去,接收方按照发送方的约定进行读取信息这样才能完整准确的获取电报信息。这里的规则就好比我们今天在互联网通讯中说的协议。不管是 HTTP 协议还是 Webservice 协议以及其他自定义协议,其实都是按照事先约定的规则,双方进行通讯。那么我们 Dubbo 中的协议其实也是一样,例如:Dubbo 中的dubbo://协议采用基于 HTTP 协议单一长连接和 NIO 异步通讯。以 HTTP 协议为例简单进行说明:

从上面时序图可以看出我们在使用 HTTP 协议时首先需要建立连接(经典的三次握手,四次挥手),然后封装发送请求报文其中包括请求头和请求体,同时响应结果中也包含响应头和响应体。这里的请求头和响应头就是我们 HTTP 通讯中的协议。
2. Dubbo 支持的协议
在 Dubbo 中支持很多中协议其中包括:
dubbo://
采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
rmi://
RMI 协议采用 JDK 标准的 java.rmi.* 实现,采用阻塞式短连接和 JDK 标准序列化方式。
hessian://
Hessian 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。
grpc://
Dubbo 自 2.7.5 版本开始支持 gRPC 协议,对于计划使用 HTTP/2 通信,或者想利用 gRPC 带来的 Stream、反压、Reactive 编程等能力的开发者来说, 都可以考虑启用 gRPC 协议。
http://
基于 HTTP 表单的远程调用协议,采用 Spring 的 HttpInvoker 实现。
injvm://
JVM 进程内调用。
redis://
基于 Redis 实现的 RPC 协议。
thrift://
当前 Dubbo 支持的 thrift 协议是对 thrift 原生协议的扩展,在原生协议的基础上添加了一些额外的头信息,比如 service name,magic number 等。
webservice://
基于 WebService 的远程调用协议。
memcached://
基于 memcached 实现的 RPC 协议。
rest://
基于标准的Java REST API—JAX-RS 2.0(Java API for RESTful Web Services的简写)实现的REST调用支持。
在这些支持的协议中dubbo://是我们最常使用的协议。
3. 示例演示
由于前面的示例中我们采用的都是dubbo://,那么本示例演示rest://协议。我们通用以获取图书列表为例,项目结构如下:

其中主要看提供者XML配置dubbo-provider-xml.xml:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<dubbo:application name="demo-provider" metadata-type="remote"/>
<!--使用rest协议-->
<dubbo:protocol name="rest" port="80" server="tomcat"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<bean id="bookFacade" class="com.muke.dubbocourse.protocol.provider.BookFacadeImpl"/>
<!--暴露本地服务为Dubbo服务-->
<dubbo:service interface="com.muke.dubbocourse.protocol.api.BookFacade" ref="bookFacade" />
</beans>
上面的 XML 配置文件中<dubbo:protocol name="rest" port="80" server="tomcat"/>协议使用rest、服务器使用tomcat、暴露端口为80。接着我们启动服务并通过浏览器访问地址:http://127.0.0.1/books/queryAll获取图书列表:

4. 原理分析
我们根据上面的示例配置来进行源码分析:当我们配置<dubbo:protocol name="rest" port="80" server="tomcat"/>时会使用org.apache.dubbo.rpc.protocol.rest.RestProtocol进行处理。这里的方法入口org.apache.dubbo.rpc.protocol.rest.RestProtocol#doExport。代码如下:
protected <T> Runnable doExport(T impl, Class<T> type, URL url) throws RpcException {
//..
RestProtocolServer server = (RestProtocolServer) serverMap.computeIfAbsent(addr, restServer -> {
//1.创建服务
RestProtocolServer s = serverFactory.createServer(url.getParameter(SERVER_KEY, DEFAULT_SERVER));
s.setAddress(url.getAddress());
//2.启动服务
s.start(url);
return s;
});
//...
}
继续跟进源码org.apache.dubbo.rpc.protocol.rest.RestServerFactory#createServer:
public RestProtocolServer createServer(String name) {
// 判断使用那种服务容器 我们这里使用tomcat
if ("servlet".equalsIgnoreCase(name) || "jetty".equalsIgnoreCase(name) || "tomcat".equalsIgnoreCase(name)) {
return new DubboHttpProtocolServer(httpBinder);
} else if ("netty".equalsIgnoreCase(name)) {
return new NettyRestProtocolServer();
} else {
throw new IllegalArgumentException("Unrecognized server name: " + name);
}
}
}
紧接着启动服务org.apache.dubbo.rpc.protocol.rest.RestProtocolServer#start:
public void start(URL url) {
//调用org.apache.dubbo.rpc.protocol.rest.DubboHttpProtocolServer#doStart
doStart(url);
}
最终调用org.apache.dubbo.rpc.protocol.rest.DubboHttpProtocolServer#doStart方法:
protected void doStart(URL url) {
// 启动Http服务容器 注意:RestHandler
httpServer = httpBinder.bind(url, new RestHandler());
//..
}
上面的代码httpBinder.bind(url, new RestHandler());非常重要org.apache.dubbo.remoting.http.tomcat.TomcatHttpBinder#bind方法创建服务容器(这里是Tomcat容器)并且绑定请求和响应处理器RestHandler,RestHandler核心代码:
private class RestHandler implements HttpHandler {
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
//使用Servlet处理所有请求
dispatcher.service(request, response);
}
}
上面的代码使用 Servlet 处理我们所有的 HTTP 请求,这也是我们最原始的处理 HTTP 请求的方式。
最后如果大家对其他协议有兴趣可以根据下面的入口去自行学习源码:

org.apache.dubbo.rpc.protocol.dubbo.DubboProtocolorg.apache.dubbo.rpc.protocol.grpc.GrpcProtocolorg.apache.dubbo.rpc.protocol.hessian.HessianProtocolorg.apache.dubbo.rpc.protocol.http.HttpProtocolorg.apache.dubbo.rpc.protocol.injvm.InjvmProtocolorg.apache.dubbo.rpc.protocol.memcached.MemcachedProtocolorg.apache.dubbo.rpc.protocol.nativethrift.ThriftProtocolorg.apache.dubbo.rpc.protocol.redis.RedisProtocolorg.apache.dubbo.rpc.protocol.rest.RestProtocolorg.apache.dubbo.rpc.protocol.rmi.RmiProtocolorg.apache.dubbo.rpc.protocol.thrift.ThriftProtocolorg.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol
5. 小结
在本小节中我们主要学习了 Dubbo 中的多协议支持,其中 Dubbo 支持11种主要的协议其中最常用的dubbo://协议。同时我们也学习了怎样去切换其他支持的协议以及协议的实现原理。
本节课程的重点如下:
- 理解 Dubbo 中多协议
- 了解怎样去切换其他支持协议
- 了解协议之间的对比差异
- 了解了多协议的实现原理
作者
个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。关注公众号:青年IT男 获取最新技术文章推送!
博客地址:
微信公众号:

浙公网安备 33010602011771号