深入浅析Netty 在 Dubbo 中是如何应用的

 更新时间:2020年05月07日 11:19:05   作者:Java技术栈  
国内知名框架 Dubbo 底层使用的是 Netty 作为网络通信,那么内部到底是如何使用的呢?今天通过本文给大家详细讲解,对Netty 在 Dubbo中应用相关知识感兴趣的朋友跟随小编一起看看吧

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

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

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

代码如下:

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 客户端,连接客户端等行为。

public AbstractClient(URL url, ChannelHandler handler) throws RemotingException {
 doOpen();
 connect();
}

doOpent 方法用来创建 Netty 的 bootstrap :

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 方法用来连接提供者:

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,稍微有点区别。点击这篇:教你用 Netty 实现一个简单的 RPC。当连接成功后,注册写事件,准备开始向提供者传递数据。

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

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 代码:

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 方法和。

代码如下:

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 调用。

到此这篇关于深入浅析Netty 在 Dubbo 中是如何应用的的文章就介绍到这了,更多相关Netty 在 Dubbo中应用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot中实现登录拦截器的代码实例

    SpringBoot中实现登录拦截器的代码实例

    这篇文章主要介绍了SpringBoot中实现登录拦截器的代码实例,对于管理系统或其他需要用户登录的系统,登录验证都是必不可少的环节,在SpringBoot开发的项目中,通过实现拦截器来实现用户登录拦截并验证,需要的朋友可以参考下
    2023-10-10
  • Spring Boot整合Redis的完整步骤

    Spring Boot整合Redis的完整步骤

    这篇文章主要给大家介绍了关于Spring Boot整合Redis的完整步骤,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05
  • Intellij idea远程debug连接tomcat实现单步调试

    Intellij idea远程debug连接tomcat实现单步调试

    这篇文章主要介绍了Intellij idea远程debug连接tomcat实现单步调试,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • Java抽奖算法第二例

    Java抽奖算法第二例

    这篇文章主要为大家详细介绍了Java抽奖算法,根据概率将奖品划分区间,每个区间代表一个奖品,然后抽取随机数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • 在java List中进行模糊查询的实现方法

    在java List中进行模糊查询的实现方法

    下面小编就为大家带来一篇在java List中进行模糊查询的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • Java IO流对文件File操作

    Java IO流对文件File操作

    这篇文章主要介绍了Java IO流对文件File操作,java封装的一个操作文件及文件夹(目录)的对象。可以操作磁盘上的任何一个文件和文件夹
    2022-12-12
  • Go Java算法之找不同示例详解

    Go Java算法之找不同示例详解

    这篇文章主要为大家介绍了Go Java算法之找不同示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 浅谈JAVA并发之ReentrantLock

    浅谈JAVA并发之ReentrantLock

    本文主要介绍了基于AQS实现的ReentrantLock(重入锁),感兴趣的同学,可以参考下。
    2021-06-06
  • java实现TCP socket和UDP socket的实例

    java实现TCP socket和UDP socket的实例

    这篇文章主要介绍了本文主要介绍了java实现TCP socket和UDP socket的实例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Java算法中的归并排序算法代码实现

    Java算法中的归并排序算法代码实现

    这篇文章主要介绍了Java算法中的归并排序算法代码实现,归并排序使用的是分治思想(Divide and Conquer),分治,顾名思义,就是分而治之,是将一个大问题分解成小的子问题来解决,需要的朋友可以参考下
    2023-12-12

最新评论