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

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

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

1240

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

1240

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);

     }


1240

通过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

相关文章
|
10天前
|
Java Maven Windows
使用Java创建集成JACOB的HTTP服务
本文介绍了如何在Java中创建一个集成JACOB的HTTP服务,使Java应用能够调用Windows的COM组件。文章详细讲解了环境配置、动态加载JACOB DLL、创建HTTP服务器、实现IP白名单及处理HTTP请求的具体步骤,帮助读者实现Java应用与Windows系统的交互。作者拥有23年编程经验,文章来源于稀土掘金。著作权归作者所有,商业转载需授权。
使用Java创建集成JACOB的HTTP服务
|
1月前
|
存储 Java
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
|
6天前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
从Java环境的搭建到实际代码的编写,从基本用法的讲解到底层原理的剖析,深度解析Java基础知识。本文是《Java学习路线》专栏的起始文章,旨在提供一套完整的Java学习路线,覆盖Java基础知识、数据库、SSM/SpringBoot等框架、Redis/MQ等中间件、设计模式、架构设计、性能调优、源码解读、核心面试题等全面的知识点,并在未来不断更新和完善,帮助Java从业者在更短的时间内成长为高级开发。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
|
6天前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
本文是Java基础的进阶篇,对异常、集合、泛型、Java8新特性、I/O流等知识进行深入浅出的介绍,并附有对应的代码示例,重要的地方带有对性能、底层原理、源码的剖析。适合Java初学者。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
|
10天前
|
Java 数据库连接 数据库
Java服务提供接口(SPI)的设计与应用剖析
Java SPI提供了一种优雅的服务扩展和动态加载机制,使得Java应用程序可以轻松地扩展功能和替换组件。通过合理的设计与应用,SPI可以大大增强Java应用的灵活性和可扩展性。
43 18
|
22天前
|
小程序 JavaScript Java
【Java】服务CPU占用率100%,教你用jstack排查定位
本文详细讲解如何使用jstack排查定位CPU高占用问题。首先介绍jstack的基本概念:它是诊断Java应用程序线程问题的工具,能生成线程堆栈快照,帮助找出程序中的瓶颈。接着,文章通过具体步骤演示如何使用`top`命令找到高CPU占用的Java进程及线程,再结合`jstack`命令获取堆栈信息并进行分析,最终定位问题代码。
100 1
【Java】服务CPU占用率100%,教你用jstack排查定位
|
6天前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(高级篇)
本文是“Java学习路线”中Java基础知识的高级篇,主要对多线程和反射进行了深入浅出的介绍,在多线程部分,详细介绍了线程的概念、生命周期、多线程的线程安全、线程通信、线程同步,并对synchronized和Lock锁;反射部分对反射的特性、功能、优缺点、适用场景等进行了介绍。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(高级篇)
|
25天前
|
Java 开发者
Java SPI机制大揭秘:动态加载服务提供者,一文让你彻底解锁!
【8月更文挑战第25天】Java SPI(服务提供者接口)是一种强大的扩展机制,允许程序在运行时动态加载服务实现。本文首先介绍SPI的基本原理——定义接口并通过配置文件指定其实现类,随后通过示例演示其实现过程。接着,对比分析了SPI与反射及插件机制的不同之处,强调SPI在灵活性与扩展性方面的优势。最后,基于不同场景推荐合适的选择策略,帮助读者深入理解并有效利用SPI机制。
33 1
|
1月前
|
消息中间件 Java API
解密微服务架构:如何在Java中实现高效的服务通信
微服务架构作为一种现代软件开发模式,通过将应用拆分成多个独立的服务,提升了系统的灵活性和扩展性。然而,实现微服务之间的高效通信仍然是许多开发者面临的挑战。本文将探讨在Java环境中实现微服务架构时,如何使用不同的通信机制来优化服务之间的交互,包括同步和异步通信的方法,以及相关的最佳实践。
|
19天前
|
开发者 C# 自然语言处理
WPF开发者必读:掌握多语言应用程序开发秘籍,带你玩转WPF国际化支持!
【8月更文挑战第31天】随着全球化的加速,开发多语言应用程序成为趋势。WPF作为一种强大的图形界面技术,提供了优秀的国际化支持,包括资源文件存储、本地化处理及用户界面元素本地化。本文将介绍WPF国际化的实现方法,通过示例代码展示如何创建和绑定资源文件,并设置应用程序语言环境,帮助开发者轻松实现多语言应用开发,满足不同地区用户的需求。
30 0