Dubbo源码学习--Http协议(三)

基于 HTTP 表单的远程调用协议,采用 Spring 的 HttpInvoker 实现 1

特性

  • 连接个数:多连接
  • 连接方式:短连接
  • 传输协议:HTTP
  • 传输方式:同步传输
  • 序列化:表单序列化
  • 适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。
  • 适用场景:需同时给应用程序和浏览器 JS 使用的服务。

约束

  • 参数及返回值需符合 Bean 规范

配置

配置协议:

<dubbo:protocol name="http" port="8080" />

配置 Jetty Server (默认):

<dubbo:protocol ... server="jetty" />

配置 Servlet Bridge Server (推荐使用):

<dubbo:protocol ... server="servlet" />

配置 DispatcherServlet:

<servlet>
         <servlet-name>dubbo</servlet-name>
         <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>
         <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
         <servlet-name>dubbo</servlet-name>
         <url-pattern>/*</url-pattern>
</servlet-mapping>

注意,如果使用 servlet 派发请求:

  • 协议的端口 <dubbo:protocol port="8080" /> 必须与 servlet 容器的端口相同,

  • 协议的上下文路径 <dubbo:protocol contextpath="foo" /> 必须与 servlet 应用的上下文路径相同。

接下来我们看看在HttpProtocol中dubbo具体做了什么逻辑处理。

HttpProtocol同样也是提供了两个接口doExport和doRefer

(1)doExport中简单来说是暴露服务,但是httpProtocol其真正是通过容器(内置容器tomcat和jetty或者外部容器)来暴露服务,其只需要将其配置初始化到容器即可。

 protected <T> Runnable doExport(final T impl, Class<T> type, URL url) throws RpcException {
		//获取暴露服务的地址
        String addr = getAddr(url);
        HttpServer server = serverMap.get(addr);
        if (server == null) {
			//将接口信息绑定到容器中
            server = httpBinder.bind(url, new InternalHandler());
            serverMap.put(addr, server);
        }
        final HttpInvokerServiceExporter httpServiceExporter = new HttpInvokerServiceExporter();
        httpServiceExporter.setServiceInterface(type);
        httpServiceExporter.setService(impl);
        try {
            httpServiceExporter.afterPropertiesSet();
        } catch (Exception e) {
            throw new RpcException(e.getMessage(), e);
        }
        final String path = url.getAbsolutePath();
        skeletonMap.put(path, httpServiceExporter);
		//创建线程,作为销毁服务时使用
        return new Runnable() {
            public void run() {
                skeletonMap.remove(path);
            }
        };
    }

(2)doRefer中简单来说就是组建远程调用的IP、端口、上下文和路径信息创建代理类,通过http协议来完成远程调用,在远程调用时消费者会根据url将要调用的接口、方法及参数信息发送给服务提供者,服务提供者根据接口和方法进行反射获取实现类,根据参数运行获取结果,在将结果返回给服务消费者。

@SuppressWarnings("unchecked")
    protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException {
        final HttpInvokerProxyFactoryBean httpProxyFactoryBean = new HttpInvokerProxyFactoryBean();
		//创建服务的url信息
        httpProxyFactoryBean.setServiceUrl(url.toIdentityString());
		//创建服务的接口信息
        httpProxyFactoryBean.setServiceInterface(serviceType);
        String client = url.getParameter(Constants.CLIENT_KEY);
        if (client == null || client.length() == 0 || "simple".equals(client)) {
			//创建连接信息
            SimpleHttpInvokerRequestExecutor httpInvokerRequestExecutor = new SimpleHttpInvokerRequestExecutor() {
                protected void prepareConnection(HttpURLConnection con,
                                                 int contentLength) throws IOException {
                    super.prepareConnection(con, contentLength);
                    con.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
                    con.setConnectTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT));
                }
            };
            httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor);
        } else if ("commons".equals(client)) {
            HttpComponentsHttpInvokerRequestExecutor httpInvokerRequestExecutor = new HttpComponentsHttpInvokerRequestExecutor();
            httpInvokerRequestExecutor.setReadTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT));
            httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor);
        } else {
            throw new IllegalStateException("Unsupported http protocol client " + client + ", only supported: simple, commons");
        }
        httpProxyFactoryBean.afterPropertiesSet();
		//创建http连接的代理类
        return (T) httpProxyFactoryBean.getObject();
    }

dubbo-py 是一个 Python 实现的 Dubbo 协议的客户端,它提供了简单易用的 API 以方便开发者在 Python 项目中使用 Dubbodubbo-py 的源代码托管在 GitHub 上,可以方便地查看和下载。 dubbo-py 的源码结构清晰,主要分为 dubbo_client 和 dubbo_codec 两个模块,其中 dubbo_client 模块实现了 Dubbo 协议的客户端,dubbo_codec 模块实现了 Dubbo 协议的序列化和反序列化操作。 在 dubbo_client 模块中,主要实现了 DubboClient 类和 DubboService 类。DubboClient 类封装了 Dubbo 协议的请求响应过程,提供 give_me_a_stub() 方法用于生成 DubboService 代理类。DubboService 类则是 Dubbo 服务实现类的代理类,使用时只需实例化 DubboService 类并调用其中的方法即可。DubboClient 和 DubboService 类的代码结构清晰,易于理解和调试。 在 dubbo_codec 模块中,主要实现了 Dubbo 协议的序列化和反序列化操作。DubboCodec 类实现了将 Python 对象转化成 Dubbo 协议要求的二进制数据,并提供了将 Dubbo 协议二进制数据转化成 Python 对象的方法。DubboCodec 类的实现较为复杂,但是提供了丰富的功能和对 Dubbo 协议的完整支持。 综上所述,dubbo-py 的源码结构清晰,实现简单易用,对 Dubbo 协议的支持非常完整。在 Python 项目中使用 Dubbo 的开发者可以通过查看 dubbo-py 的源码学习 Dubbo 客户端的实现方法和 Dubbo 协议的序列化和反序列化操作,提高自己的技术水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值