前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Netty-在-Dubbo-中如何应用

Netty-在-Dubbo-中如何应用

作者头像
用户5224393
发布于 2019-08-13 06:55:48
发布于 2019-08-13 06:55:48
1.2K00
代码可运行
举报
文章被收录于专栏:Java研发军团Java研发军团
运行总次数:0
代码可运行

作者:莫那鲁道

链接:http://thinkinjava.cn/2018/03/%E7%9C%8B-Netty-%E5%9C%A8-Dubbo-%E4%B8%AD%E5%A6%82%E4%BD%95%E5%BA%94%E7%94%A8/

目录

  1. dubbo 的 Consumer 消费者如何使用 Netty
  2. dubbo 的 Provider 提供者如何使用 Netty
  3. 总结

前言

众所周知,国内知名框架 Dubbo 底层使用的是 Netty 作为网络通信,那么内部到底是如何使用的呢?今天我们就来一探究竟。

1. dubbo 的 Consumer 消费者如何使用 Netty

注意:此次代码使用了从 github 上 clone 的 dubbo 源码中的 dubbo-demo 例子。

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
System.setProperty("java.net.preferIPv4Stack", "true");
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
    context.start();
     // @1
    DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy
    int a = 0;
    while (true) {
        try {
            Thread.sleep(1000);
            System.err.println( ++ a + " ");

            String hello = demoService.sayHello("world"); // call remote method
            System.out.println(hello); // get result

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

当代码执行到 @1 的时候,会调用 Spring 容器的 getBean 方法,而 dubbo 扩展了 FactoryBean,所以,会调用 getObject 方法,该方法会创建代理对象。

这个过程中会调用 DubboProtocol 实例的 getClients(URL url) 方法,当这个给定的 URL 的 client 没有初始化则创建,然后放入缓存,代码如下:

这个 initClient 方法就是创建 Netty 的 client 的。

最终调用的就是抽象父类 AbstractClient 的构造方法,构造方法中包含了创建 Socket 客户端,连接客户端等行为。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public AbstractClient(URL url, ChannelHandler handler) throws RemotingException {
    doOpen();
    connect();
}

doOpent 方法用来创建 Netty 的 bootstrap :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void doOpen() throws Throwable {
    NettyHelper.setNettyLoggerFactory();
    bootstrap = new ClientBootstrap(channelFactory);
    bootstrap.setOption("keepAlive", true);
    bootstrap.setOption("tcpNoDelay", true);
    bootstrap.setOption("connectTimeoutMillis", getTimeout());
    final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
    bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() {
            NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
            ChannelPipeline pipeline = Channels.pipeline();
            pipeline.addLast("decoder", adapter.getDecoder());
            pipeline.addLast("encoder", adapter.getEncoder());
            pipeline.addLast("handler", nettyHandler);
            return pipeline;
        }
    });
}

connect 方法用来连接提供者:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected void doConnect() throws Throwable {
    long start = System.currentTimeMillis();
    ChannelFuture future = bootstrap.connect(getConnectAddress());
    boolean ret = future.awaitUninterruptibly(getConnectTimeout(), TimeUnit.MILLISECONDS);
    if (ret && future.isSuccess()) {
        Channel newChannel = future.getChannel();
        newChannel.setInterestOps(Channel.OP_READ_WRITE);
    } 
}

上面的代码中,调用了 bootstrap 的 connect 方法,熟悉的 Netty 连接操作。当然这里使用的是 jboss 的 netty3,稍微有点区别。当连接成功后,注册写事件,准备开始向提供者传递数据。

当 main 方法中调用 demoService.sayHello(“world”) 的时候,最终会调用 HeaderExchangeChannel 的 request 方法,通过 channel 进行请求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public ResponseFuture request(Object request, int timeout) throws RemotingException {
    Request req = new Request();
    req.setVersion("2.0.0");
    req.setTwoWay(true);
    req.setData(request);
    DefaultFuture future = new DefaultFuture(channel, req, timeout);
    channel.send(req);
    return future;
}

send 方法中最后调用 jboss Netty 中继承了 NioSocketChannel 的 NioClientSocketChannel 的 write 方法。完成了一次数据的传输。

2. dubbo 的 Provider 提供者如何使用 Netty

Provider demo 代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
System.setProperty("java.net.preferIPv4Stack", "true");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
context.start();
System.in.read(); // press any key to exit

Provider 作为被访问方,肯定是一个 Server 模式的 Socket。如何启动的呢?

当 Spring 容器启动的时候,会调用一些扩展类的初始化方法,比如继承了 InitializingBean,ApplicationContextAware,ApplicationListener 。

而 dubbo 创建了 ServiceBean 继承了一个监听器。Spring 会调用他的 onApplicationEvent 方法,该类有一个 export 方法,用于打开 ServerSocket 。

然后执行了 DubboProtocol 的 createServer 方法,然后创建了一个 NettyServer 对象。NettyServer 对象的 构造方法同样是 doOpen 方法和。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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();
    bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() {
            NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
            ChannelPipeline pipeline = Channels.pipeline();
            pipeline.addLast("decoder", adapter.getDecoder());
            pipeline.addLast("encoder", adapter.getEncoder());
            pipeline.addLast("handler", nettyHandler);
            return pipeline;
        }
    });
    channel = bootstrap.bind(getBindAddress());
}

该方法中,看到了熟悉的 boss 线程,worker 线程,和 ServerBootstrap,在添加了编解码 handler 之后,添加一个 NettyHandler,最后调用 bind 方法,完成绑定端口的工作。和我们使用 Netty 是一摸一样。

3. 总结

可以看到,dubbo 使用 Netty 还是挺简单的,消费者使用 NettyClient,提供者使用 NettyServer,Provider 启动的时候,会开启端口监听,使用我们平时启动 Netty 一样的方式。

而 Client 在 Spring getBean 的时候,会创建 Client,当调用远程方法的时候,将数据通过 dubbo 协议编码发送到 NettyServer,然后 NettServer 收到数据后解码,并调用本地方法,并返回数据,完成一次完美的 RPC 调用。

好,关于 dubbo 如何使用 Netty 就简短的介绍到这里。

END

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java研发军团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
手写dubbo 10-基于netty实现RPC
博客中代码地址:https://github.com/farliu/farpc.git
并发笔记
2020/11/09
1.2K0
Netty在Dubbo中的使用过程源码分析
最近项目中使用了netty服务,空余时间差了下dubbo中是如何使用netty做底层服务的,找了相关资料记录一下:
小勇DW3
2020/04/26
8020
Java学习笔记——dubbo服务之底层通讯协议Protocol
我们先来找到通讯协议的入口点吧。通过Protocol接口查找通讯协议入口点,我们根据接口的export方法搜索发现入口了,在ServiceConfig的doExportUrlsFor1Protocol方法,如下图:
慕容千语
2019/06/11
1.2K0
源码分析Dubbo服务提供者启动流程-下篇
本文继续上文Dubbo服务提供者启动流程,在上篇文章中详细梳理了基于dubbo spring文件的配置方式,Dubbo是如何加载配置文件,服务提供者dubbo:service标签服务暴露全流程,本节重点关注RegistryProtocol#export中调用doLocalExport方法,根据服务暴露协议建立网络通讯服务器,在特定端口建立监听,监听来自消息消费端服务的请求。
丁威
2019/06/10
8080
源码分析Dubbo服务提供者启动流程-下篇
dubbo源码学习(四):暴露服务的过程
dubbo采用的nio异步的通信,通信协议默认为 netty,当然也可以选择 mina,grizzy。在服务端(provider)在启动时主要是开启netty监听,在zookeeper上注册服务节点,处理消费者请求,返回处理后的消息给消费者,消费者使用服务时主要是订阅服务的节点,监听zookeeper节点目录,服务端的变化时zookeeper会推送给消费者,消费者重新缓存服务地址等。服务者、消费者、zookeeper三者之间都是长连接。
BUG弄潮儿
2022/06/30
3210
dubbo源码学习(四):暴露服务的过程
【DUBBO】 服务引用RegistryDirectory
实现了FactoryBean接口,所以在获取实例的时候,实际上是调用getObject方法返回实例。这里面的get方法继承自ReferenceConfig类
spilledyear
2018/12/24
8450
源码分析Dubbo NettyServer与HeaderExchangeServer
本文主要分析一下NettyServer,HeaderExchangeServer实现细节。
丁威
2019/06/10
7010
源码分析Dubbo NettyServer与HeaderExchangeServer
dubbo源码学习三——暴露服务exporter、invoker
前面我们知道通过自定义标签,我们可以定位到相关标签的解析,同时梳理出三个重要的bean:ServiceBean、ReferenceBean、ConfigCenterBean。而通过Servicebean,可以看到ServiceConfig中有我们关注的export方法,而通过export,我们可以看到其暴露服务,又分为本地暴露和远程暴露两种,而暴露之前,会进行配置的检查,然后进行url的组装操作,接着进行exporter,而暴露之前,会进行getInvoker操作。而在getInvoker操作中,首先会进行适配,然后进行动态代理模板生成,生成class文件。而export操作中,进入到RegisterProtocol中,export又分为暴露doLocalExport(originInvoker, providerUrl)——>protocol.export(invokerDelegate)——>DubboProtocol#export(Invoker<T> invoker),完成配置的放入map之后,进行服务器开启openServer(url),进行双重校验创建服务器createServer(url)-——> Exchangers.bind(url, requestHandler)——>getExchanger(url).bind(url, handler)——>HanderExchanger#bind(URL url, ExchangeHandler handler)——>Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))——> getTransporter().bind(url, handler)——>NettyTransporter#NettyServer(url, listener)——>NettyServer#doOpen()_——>ServerBootstrap# bind(final SocketAddress localAddress),进行配置的和注册、订阅过程。暴露的过程又是首先进行适配,然后适配之后,进行到dubboProtocol中,进行getInvoker操作。
路行的亚洲
2020/07/17
1.5K0
Dubbo性能调优参数及原理
其中,Constants.DEFAULT_QUEUES = 200。threads 参数配置的是业务处理线程池的最大(或核心)线程数。
烂猪皮
2018/08/03
1.8K0
Dubbo性能调优参数及原理
《Dubbo进阶一》——RPC协议底层原理
在一个典型的RPC的使用场景中,包含了服务发现、负载、容错、序列化和网络传输等组件,其中RPC协议指明了程序如何进行序列化和网络传输,也就是说一个RPC协议的实现等于一个非透明的RPC调用。
全栈程序员站长
2022/08/30
7070
《Dubbo进阶一》——RPC协议底层原理
源码分析Dubbo服务调用-服务提供者如何处理请求命令与再谈Invoker
本文将重点剖析服务调用流程,也就是消费端通过网络发起RPC服务调用时,服务提供者是如何进行服务请求响应的。
丁威
2019/06/10
5870
源码分析Dubbo服务调用-服务提供者如何处理请求命令与再谈Invoker
dubbo服务暴露过程源码分析
本例以一个简单典型的服务发布为例,spring配置如下 //dubbo协议 <dubbo:protocol name="dubbo" port="20880" id="dubbo1"/> //zk注册中心 <dubbo:registry id="hangzhouRegistry" address="zookeeper://192.168.64.128:2181"/> <dubbo:service interface="demo.dubbo.api.DemoService" ref="dem
技术蓝海
2018/04/26
2K0
Dubbo系列四之dubbo协议数据收发细节
由之前的文章可知,Consumer最终在生成DubboInvoker时,会生成对应的客户端连接,如下
用户9511949
2024/08/09
1610
Netty 的 Channel、Promise、Pipeline 详解
首先通过一个示例来分析,创建一个 NioServerSocketChannel 监听本机端口 11111 的 Socket 连接,将收到的消息原样返回;然后再创建一个 NioSocketChannel,发起对本机的 11111 端口的 Socket 连接,发送字符串 ”Netty rocks!“。预期能收到服务端返回的 “Netty rocks!” 响应。
Yano_nankai
2019/11/10
4.4K0
Netty 的 Channel、Promise、Pipeline 详解
聊聊dubbo的NettyServer
dubbo-2.7.3/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractServer.java
code4it
2019/08/30
8760
聊聊dubbo的NettyServer
Dubbo 编解码那些事
笔者在一次维护基础公共组件的过程中,不小心修改了类的包路径。糟糕的是,这个类被各业务在facade中进行了引用、传递。幸运的是,同一个类,在提供者和消费者的包路径不一致,没有引起各业务报错。
2020labs小助手
2021/04/13
7310
Dubbo 源码分析 - 服务导出全过程解析
本篇文章,我们来研究一下 Dubbo 导出服务的过程。Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑。整个逻辑大致可分为三个部分,第一是前置工作,主要用于检查参数,组装 URL。第二是导出服务,包含导出服务到本地 (JVM),和导出服务到远程两个过程。第三是向注册中心注册服务,用于服务发现。本篇文章将会对这三个部分代码进行详细的分析,在分析之前,我们先来了解一下服务的导出过程。
田小波
2018/12/05
6990
Dubbo 源码分析 - 服务导出全过程解析
Dubbo源码学习五-服务发现
从类图中,我们可以看到ReferenceBean继承了Referenceconfig,同时实现了FactoryBean、DisposableBean、ApplicationContextAware、InitializingBean,因此可以看到里面会有相应的aware方法、相应的destroy方法、 AfterPropertiesSet方法,这里我们重点关注AfterPropertiesSet方法。因为其是spring留给我们进行扩展的一个通道。
路行的亚洲
2020/07/17
9730
Dubbo RPC在consumer端是如何跑起来的
在分析dubbo consumer端的RPC实现之前,首先来看下dubbo的整体架构,有个整体概念。
luoxn28
2020/07/10
9900
Dubbo RPC在consumer端是如何跑起来的
dubbo学习(四)provider服务发布
Export dubbo service com.ywl.dubbo.TestApi to local registry, dubbo version: 2.0.0, current host: 127.0.0.1。
虞大大
2020/10/09
1.2K0
相关推荐
手写dubbo 10-基于netty实现RPC
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验