Java学习笔记——dubbo服务之底层通讯协议Protocol

简介: 我们先来找到通讯协议的入口点吧。通过Protocol接口查找通讯协议入口点,我们根据接口的export方法搜索发现入口了,在ServiceConfig的doExportUrlsFor1Protocol方法,如下图:然后我们进入 protocol.

我们先来找到通讯协议的入口点吧。通过Protocol接口查找通讯协议入口点,我们根据接口的export方法搜索发现入口了,在ServiceConfig的doExportUrlsFor1Protocol方法,如下图:


然后我们进入 protocol.export(invoker)方法发现有很多实现类,根据spi(不懂的请看之前写的容器篇)查看配置文件能找到如下


registry=com.alibaba.dubbo.registry.integration.RegistryProtocol

dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol   //这个是默认的,我们在Protocol接口上可以看到spi的注解

filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper

listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper

mock=com.alibaba.dubbo.rpc.support.MockProtocol

injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol

rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol

hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol

com.alibaba.dubbo.rpc.protocol.http.HttpProtocol

com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol

thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol

memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol

redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol

rest=com.alibaba.dubbo.rpc.protocol.rest.RestProtocol

进入DubboProtocol.export(Invoker<T> invoker)方法里面有个 openServer(url);

代码:

  private void openServer(URL url) {

        // find server.

        String key = url.getAddress();

        //client 也可以暴露一个只有server可以调用的服务。

        boolean isServer = url.getParameter(Constants.IS_SERVER_KEY,true);

        if (isServer) {

        ExchangeServer server = serverMap.get(key);

        if (server == null) {

        serverMap.put(key, createServer(url)); //createServer是创建服务

        } else {

        //server支持reset,配合override功能使用

        server.reset(url);

        }

        }

    }


继续进入createServer,上源码


    private ExchangeServer createServer(URL url) {

        //默认开启server关闭时发送readonly事件

        url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());

        //默认开启heartbeat

        url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));

        String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);

        if (str != null && str.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))

            throw new RpcException("Unsupported server type: " + str + ", url: " + url);

        url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME);

        ExchangeServer server;

        try {

            server = Exchangers.bind(url, requestHandler);

        } catch (RemotingException e) {

            throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);

        }

        str = url.getParameter(Constants.CLIENT_KEY);

        if (str != null && str.length() > 0) {

            Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();

            if (!supportedTypes.contains(str)) {

                throw new RpcException("Unsupported client type: " + str);

            }

        }

        return server;

    }


    dubbo从要暴漏的服务的URL中取得相关的配置(host,port等)进行服务端server的创建,同上面的server = Exchangers.bind(url, requestHandler) 正式创建服务。

    所以基本的创建步骤是

   export()  -->  openServer()  -->  createServer()  -->  server = Exchangers.bind(url, requestHandler);  



  我们进行来看 Exchangers.bind(url, requestHandler)


  源码:

public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {

      if (url == null) {

          throw new IllegalArgumentException("url == null");

      }

      if (handler == null) {

          throw new IllegalArgumentException("handler == null");

      }

      url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");

      return getExchanger(url).bind(url, handler);

  }


  然后通过getExchanger(url).bind(url, handler)的bing进入 HeaderExchanger类


  public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {

        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));

    }

    在进入Transporters类的bing的


  public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {

         if (url == null) {

             throw new IllegalArgumentException("url == null");

         }

         if (handlers == null || handlers.length == 0) {

             throw new IllegalArgumentException("handlers == null");

         }

         ChannelHandler handler;

         if (handlers.length == 1) {

             handler = handlers[0];

         } else {

             handler = new ChannelHandlerDispatcher(handlers);

         }

         return getTransporter().bind(url, handler);

     }



通过bing可以知道他讲调用:GrizzlyTransporter,MinaTransporter,NettyTransporter 通过spi默认是调用NettyTransporter

     到这里我们基本明白dubbo的通讯默认是交给了netty来处理,


     我们在看下doOPen方法


@Override

        protected void doOpen() throws Throwable {

            NettyHelper.setNettyLoggerFactory();

            ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));

            ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));

            ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));

            bootstrap = new ServerBootstrap(channelFactory);


            final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);

            channels = nettyHandler.getChannels();

            // https://issues.jboss.org/browse/NETTY-365

            // https://issues.jboss.org/browse/NETTY-379

            // final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));

            bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

                public ChannelPipeline getPipeline() {

                    NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec() ,getUrl(), NettyServer.this);

                    ChannelPipeline pipeline = Channels.pipeline();

                    /*int idleTimeout = getIdleTimeout();

                    if (idleTimeout > 10000) {

                        pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0));

                    }*/

                    pipeline.addLast("decoder", adapter.getDecoder());//解码

                    pipeline.addLast("encoder", adapter.getEncoder());//编码

                    pipeline.addLast("handler", nettyHandler);

                    return pipeline;

                }

            });

            // bind

            channel = bootstrap.bind(getBindAddress());

        }


 了解netty的同学,肯定早已习惯这个方法的写法,就是创建了netty的server嘛,到这里dubbo的服务创建完毕了,这个时候控制台见打印:

 [DUBBO] Start NettyServer bind /0.0.0.0:20880, export /192.168.4.241:20880, dubbo version: 2.8.4, current host: 127.0.0.1

相关文章
|
5月前
|
JSON Java 数据格式
java调用服务报错400
java调用服务报错400
143 6
java调用服务报错400
|
5月前
|
JSON Java 数据格式
java调用服务报错415 Content type ‘application/octet-stream‘ not supported
java调用服务报错415 Content type ‘application/octet-stream‘ not supported
358 6
|
6月前
|
Java
Java 数组学习笔记
本文整理Java数组常用操作:遍历、求和、查找、最值及二维数组行求和等典型练习,涵盖静态初始化、元素翻倍、去极值求平均等实例,帮助掌握数组基础与应用。
|
6月前
|
小程序 Java 知识图谱
Java 学习笔记 —— BMI & BMR 计算器
这是一个使用 Java 编写的 BMI 与 BMR 计算器小程序,可输入年龄、性别、身高和体重,计算身体质量指数(BMI)和基础代谢率(BMR),并输出健康评估结果。通过该项目,掌握了 Java 的输入处理、数据验证、条件判断、数学运算及格式化输出等基础知识,是 Java 初学者的理想练习项目。
|
7月前
|
存储 数据采集 搜索推荐
Java 大视界 -- Java 大数据在智慧文旅旅游景区游客情感分析与服务改进中的应用实践(226)
本篇文章探讨了 Java 大数据在智慧文旅景区中的创新应用,重点分析了如何通过数据采集、情感分析与可视化等技术,挖掘游客情感需求,进而优化景区服务。文章结合实际案例,展示了 Java 在数据处理与智能推荐等方面的强大能力,为文旅行业的智慧化升级提供了可行路径。
Java 大视界 -- Java 大数据在智慧文旅旅游景区游客情感分析与服务改进中的应用实践(226)
|
8月前
|
分布式计算 搜索推荐 算法
Java 大视界 -- Java 大数据在智慧养老服务需求分析与个性化服务匹配中的应用(186)
本篇文章探讨了Java大数据技术在智慧养老服务需求分析与个性化服务匹配中的应用。通过整合老年人健康数据与行为数据,结合机器学习与推荐算法,实现对老年人健康风险的预测及个性化服务推荐,提升养老服务的智能化与精准化水平,助力智慧养老高质量发展。
|
9月前
|
Java API 微服务
2025 年 Java 从入门到精通学习笔记全新版
《Java学习笔记:从入门到精通(2025更新版)》是一本全面覆盖Java开发核心技能的指南,适合零基础到高级开发者。内容包括Java基础(如开发环境配置、核心语法增强)、面向对象编程(密封类、接口增强)、进阶技术(虚拟线程、结构化并发、向量API)、实用类库与框架(HTTP客户端、Spring Boot)、微服务与云原生(容器化、Kubernetes)、响应式编程(Reactor、WebFlux)、函数式编程(Stream API)、测试技术(JUnit 5、Mockito)、数据持久化(JPA、R2DBC)以及实战项目(Todo应用)。
484 5
|
12月前
|
存储 Java
# 【Java全栈学习笔记-U1-day02】变量+数据类型+运算符
本篇笔记主要围绕Java全栈学习的第二天内容展开,涵盖了变量、数据类型、运算符以及Scanner类的应用。首先介绍了变量的概念与命名规范,以及如何定义和使用变量;接着详细讲解了Java中的基本数据类型,包括整型、浮点型、字符型、布尔型等,并通过实例演示了数据类型的运用。随后,深入探讨了各类运算符(赋值、算术、关系、逻辑)及其优先级,帮助理解表达式的构成。最后,介绍了如何利用Scanner类实现用户输入功能,并通过多个综合示例(如计算圆面积、购物打折、变量交换及银行利息计算)巩固所学知识。完成相关作业将进一步加深对这些基础概念的理解与实践能力。
231 13
|
5月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
286 1

热门文章

最新文章