目录:

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

前言

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

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

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

代码如下:

  1. System.setProperty("java.net.preferIPv4Stack", "true");
  2. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
  3. context.start();
  4. // @1
  5. DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy
  6. int a = 0;
  7. while (true) {
  8. try {
  9. Thread.sleep(1000);
  10. System.err.println( ++ a + " ");
  11. String hello = demoService.sayHello("world"); // call remote method
  12. System.out.println(hello); // get result
  13. } catch (Throwable throwable) {
  14. throwable.printStackTrace();
  15. }
  16. }

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

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

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

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

  1. public AbstractClient(URL url, ChannelHandler handler) throws RemotingException {
  2. doOpen();
  3. connect();
  4. }

doOpent 方法用来创建 Netty 的 bootstrap :

  1. protected void doOpen() throws Throwable {
  2. NettyHelper.setNettyLoggerFactory();
  3. bootstrap = new ClientBootstrap(channelFactory);
  4. bootstrap.setOption("keepAlive", true);
  5. bootstrap.setOption("tcpNoDelay", true);
  6. bootstrap.setOption("connectTimeoutMillis", getTimeout());
  7. final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
  8. bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
  9. public ChannelPipeline getPipeline() {
  10. NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
  11. ChannelPipeline pipeline = Channels.pipeline();
  12. pipeline.addLast("decoder", adapter.getDecoder());
  13. pipeline.addLast("encoder", adapter.getEncoder());
  14. pipeline.addLast("handler", nettyHandler);
  15. return pipeline;
  16. }
  17. });
  18. }

connect 方法用来连接提供者:

  1. protected void doConnect() throws Throwable {
  2. long start = System.currentTimeMillis();
  3. ChannelFuture future = bootstrap.connect(getConnectAddress());
  4. boolean ret = future.awaitUninterruptibly(getConnectTimeout(), TimeUnit.MILLISECONDS);
  5. if (ret && future.isSuccess()) {
  6. Channel newChannel = future.getChannel();
  7. newChannel.setInterestOps(Channel.OP_READ_WRITE);
  8. }
  9. }

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

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

  1. public ResponseFuture request(Object request, int timeout) throws RemotingException {
  2. Request req = new Request();
  3. req.setVersion("2.0.0");
  4. req.setTwoWay(true);
  5. req.setData(request);
  6. DefaultFuture future = new DefaultFuture(channel, req, timeout);
  7. channel.send(req);
  8. return future;
  9. }

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

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

Provider demo 代码:

  1. System.setProperty("java.net.preferIPv4Stack", "true");
  2. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
  3. context.start();
  4. 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 方法和。代码如下:

  1. protected void doOpen() throws Throwable {
  2. NettyHelper.setNettyLoggerFactory();
  3. ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
  4. ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
  5. ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
  6. bootstrap = new ServerBootstrap(channelFactory);
  7. final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
  8. channels = nettyHandler.getChannels();
  9. bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
  10. public ChannelPipeline getPipeline() {
  11. NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
  12. ChannelPipeline pipeline = Channels.pipeline();
  13. pipeline.addLast("decoder", adapter.getDecoder());
  14. pipeline.addLast("encoder", adapter.getEncoder());
  15. pipeline.addLast("handler", nettyHandler);
  16. return pipeline;
  17. }
  18. });
  19. channel = bootstrap.bind(getBindAddress());
  20. }

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

3. 总结

可以看到,dubbo 使用 Netty 还是挺简单的,消费者使用 NettyClient,提供者使用 NettyServer,Provider 启动的时候,会开启端口监听,使用我们平时启动 Netty 一样的方式。而 Client 在 Spring getBean 的时候,会创建 Client,当调用远程方法的时候,将数据通过 dubbo 协议编码发送到 NettyServer,然后 NettServer 收到数据后解码,并调用本地方法,并返回数据,完成一次完美的 RPC 调用。

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

good luck!!!!

看 Netty 在 Dubbo 中如何应用的更多相关文章

  1. 在dubbo的一端,看Netty处理数据包,揭网络传输原理

    如今,我们想要开发一个网络应用,那是相当地方便.不过就是引入一个框架,然后设置些参数,然后写写业务代码就搞定了. 写业务代码自然很重要,但是你知道: 你的数据是怎么来的吗?通过网络传输过来的呗. 你知 ...

  2. 架构师之路-在Dubbo中开发REST风格的远程调用

    架构师之路:从无到有搭建中小型互联网公司后台服务架构与运维架构 http://www.roncoo.com/course/view/ae1dbb70496349d3a8899b6c68f7d10b 概 ...

  3. Dubbo中服务消费者和服务提供者之间的请求和响应过程

    服务提供者初始化完成之后,对外暴露Exporter.服务消费者初始化完成之后,得到的是Proxy代理,方法调用的时候就是调用代理. 服务消费者经过初始化之后,得到的是一个动态代理类,InvokerIn ...

  4. Dubbo中消费者初始化的过程解析

    首先还是Spring碰到dubbo的标签之后,会使用parseCustomElement解析dubbo标签,使用的解析器是dubbo的DubboBeanDefinitionParser,解析完成之后返 ...

  5. Dubbo中编码和解码的解析

    (这里做的解析不是很详细,等到走完整个流程再来解析)Dubbo中编解码的工作由Codec2接口的实现来处理,回想一下第一次接触到Codec2相关的内容是在服务端暴露服务的时候,根据具体的协议去暴露服务 ...

  6. Dubbo中暴露服务的过程解析

    dubbo暴露服务有两种情况,一种是设置了延迟暴露(比如delay="5000"),另外一种是没有设置延迟暴露或者延迟设置为-1(delay="-1"): 设置 ...

  7. 【Rest】在Dubbo中开发REST风格的远程调用(RESTful Remoting)

    目录 概述 REST的优点 应用场景 快速入门 标准Java REST API:JAX-RS简介 REST服务提供端详解 HTTP POST/GET的实现 Annotation放在接口类还是实现类 J ...

  8. Dubbo中@Service工作过程解析

    Dubbo中@Service工作过程解析 Spring中的BeanPostProcessor 首先我们应当了解到在spring体系中BeanPostProcessor是什么.加载流程 它是什么 Bea ...

  9. Dubbo中订阅和通知解析

    Dubbo中关于服务的订阅和通知主要发生在服务提供方暴露服务的过程和服务消费方初始化时候引用服务的过程中. 2345678910111213141516171819 public <T> ...

随机推荐

  1. MCU_头文件编写

    头文件中一般放一些重复使用的代码,如:常量.变量.宏等的定义,函数的声明.当使用#include语句引用头头文件时,相当于将头文件中的内容复制到#include处. 头文件一般形式: #ifndef  ...

  2. Android-Java-synchronized同步锁机制&利与弊

    synchronized同步锁机制 定义锁

  3. PSP个人项目耗时对比记录表:四则运算

    Personal Software Process Stages Time(%) 计划 5    •估计这个任务需要多长时间 5 开发 60    •需求分析  5    •生成设计文档  5     ...

  4. 2015-2016-1 学期《软件工程》学生名单-- PS:教材使用《构建之法》第二版 --邹欣著

    1208053044 王威 男 1313023001 饶阳梅 女 1313023002 应蕾蕾 女 1313023004 袁立萍 女 1313023005 黎洋阳 女 1313023006 蒋欣 女 ...

  5. Network in Network 个人理解

    关键点是1*1的卷积是怎么用的,也就是MLP卷积.看如下的数据就可以理解了 输入为224*224*3的图像,第一层卷积为11*11*3*96(也就是96个11*11*3的卷积核,另外还有步长),卷积完 ...

  6. 使用PerfView监测.NET程序性能(一):Event Trace for Windows

    前言: 在日常项目开发中,我们时不时会遇到程序占用了很高CPU的情况,可能是程序里某些未经优化的代码或者Bug,或者是程序运行压力太大.无论是什么原因,我们总希望能看到到底是哪个方法占用了如此高的CP ...

  7. 设置 Nuget 本地源、在线私有源、自动构建打包

    设置 Nuget 本地源.在线私有源.自动构建打包 本文演示如果在项目中生成 Nuget 包,并添加 Nuget 本地源,不用发布到 Nuget 服务器.再附带使用在线私有源的简单方法,以及提交代码自 ...

  8. WPF Bitmap转成Imagesource的性能优化

    之前有个需求是在WPF中生成二维码,用的是QRCoder. QRCoder生成的是Bitmap,在wpf中需要转换成ImageSource才能显示. 之前的转换方式是: IntPtr hBitmap ...

  9. Button去除边框方法

    <Button  Content="Button" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey} ...

  10. 浏览器环境下JavaScript脚本加载与执行探析之代码执行顺序

    本文主要基于向HTML页面引入JavaScript的几种方式,分析HTML中JavaScript脚本的执行顺序问题 1. 关于JavaScript脚本执行的阻塞性 JavaScript在浏览器中被解析 ...