注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小葫芦君(汉斯的博客)

博客迁移到新博客:https://blog.ssxingshou.com

 
 
 

日志

 
 
关于我

小小葫芦商城,为您提供高品质的商品,一流的产品,一流的包装服务,一流的物流服务,放心购买

网易考拉推荐

Netty 4.0 新的特性及需要注意的地方 6  

2014-04-11 21:55:51|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

良好定义的线程模型

在3.x里并没有良好设计的线程模型,尽管曾经要修复线程模型在3.5的不一致性。4.0定义的一个严格的线程模型来帮助用户编写ChannelHandler而不必担心太多关于线程安全的东西。

  • Netty将不会再同步地调用ChannelHandler的方法了,除非ChannelHandler由@Shareable注解。这不会理会处理器方法的类似——入站、操作、或者是生命周期时间处理器方法。
    • 用户不再需要同步入站或出站的事件处理器方法。
    • 4.0不允许加入加入一个ChannelHandler超过一次,除非它由@Sharable注解。
  • 每个由Netty调用的ChannelHandler的方法之间的关系总是happens-before
    • 用户不用定义一个volatile字段来保存处理器的状态。
  • 用户能够在他加入一个处理器到ChannelPipeline的时候指定EventExecutor。
    • 如果有指定,ChannelHandler的处理器方法总是由自动的EventExecutor来调用
    • 如果没指定,处理器方法总是由它关联的Channel注册到的EventLoop来调用。
  • 声明到一个处理器的EventExecutor和EventLoop总是单线程的。
    • 处理器方法总是由相同线程调用。
    • 如果指定了多线程的EventExecutor或EventLoop,线程中的一个会被选择,然后选择到的线程将会被使用,直到取消注册。
    • 如果在相同管道里的两个处理器声明到不同的EventExecutor,它们会同时被调用。如果多个一个处理器去访问共享数据,用户需要注意线程安全,即使共享数据只能被相同管道里的处理器访问。
  • 加入到ChannelFuture的ChannelFutureListener总是由关联到future相关的Channel的EventLoop线程调用。

    不再有ExecutionHandler ——它包含到核心里

    在你加入一个ChannelHandler到一个ChannelPipeline来告诉管道总是通过指定的EventExecutor调用加入的ChannelHander处理器的方法的时候,你可以指定一个EventExecutor。

    1Channel ch = ...;
    2ChannelPipeline p = ch.pipeline();
    3EventExecutor e1 = new DefaultEventExecutor(16);
    4EventExecutor e2 = new DefaultEventExecutor(8);
    5  
    6p.addLast(new MyProtocolCodec());
    7p.addLast(e1, new MyDatabaseAccessingHandler());
    8p.addLast(e2, new MyHardDiskAccessingHandler());

    EventExecutor是EventLoop的超类,同时也继承了ScheduledExecutorService。

    fixme

    编码解码器框架变化

    在编码解码器框架里有实质性的内部改变,因为4.0需要一个处理器来创建和管理它的缓存(看这篇文章的每个处理器缓存部分。)然而,从用户角度来看这些变化都不是很大的。

    • 核心编码界面器类移到io.netty.handler.codec包里。
    • FrameDecoder重命名为ByteToMessageDecoder。
    • OneToOneEncoder和OneToOneDecoder由MessageToMessageEncoder和MessageToMessageDecoder替换。
    • decode(),decodeLast(),encode()的方法前面稍微改变了来支持泛型同时移除冗余参数。

      编码解码器嵌入器→ EmbeddedChannel

      编码解码器嵌入器已经被 io.netty.channel.embedded.EmbeddedByteChannel和EmbeddedMessageChannel替换了。EmbeddedChannel允许用户对任何包含编码解码器的管道进行单元测试。

      HTTP编码解码器

      HTTP解码器现在在每个HTTP消息中总生成多个消息对象:

      11       * HttpRequest / HttpResponse
      20 - n   * HttpContent
      31       * LastHttpContent

      要看更多的细节,请到转到已更新了的HttpSnoopServer例子。如果你希望为一个单一的HTTP消息处理多个消息,你可以把HttpObjectAggregator放入管道里。HttpObjectAggregator会把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse。

      传输实现的变化

      下面是传输协议新加入的东西:

      • 使用NIO.2AsynchronousSocketChannel的AIO套接字传输实现。
      • OIO SCTP 传输实现
      • UDT 传输实现

        用例学习:移植示例Factorial

        这部分粗略地展示把示例Factorial从3.0移植到4.0的步骤。示例Factorial已经移植到4.0了,它放在io.netty.example.factorial包里。请浏览示例的源代码来看下每一处的变化。

        移植服务端

        1. 重写FactorialServer.run()方法来使用新的 bootstrap API。
          1. 不再有ChannelFactory了。 由你自己去实例化NioEventLoop(一个是用来接收接入的链接,另外的就用来处理接收到的链接)。
        2. 从命名FactorialServerPipelineFactory为FactorialServerInitializer。
          1. 让它继承ChannelInitializer<Channel>。
          2. 取代创建新的ChannelPipeline,通过Channel.pipeline()来获取。
        3. 让FactorialServerHandler继承sChannelInboundMessageHandlerAdapter<BigInteger>。
          1. 用channelInactive()来替换channelDisconnected()。
          2. handleUpstream()不能再使用了。
        4. 让BigIntegerDecoder继承ByteToMessageDecoder<BigInteger>。
        5. 让NumberEncoder继承MessageToByteEncoder<Number>。
          1. encode()不在返回一个缓存了。由ByteToMessageDecoder来提供填充编码好的数据到缓存里。

            移植客户端

            大部分和移植服务端差不多,但你要在你编写一个潜在的大数据流时要多注意下。

            1. 重写FactorialClient.run()方法来使用新的bootstrap API。
            2. 重命名FactorialClientPipelineFactory为FactorialClientInitializer。
            3. 使FactorialClientHandler继承ChannelInboundMessageHandlerAdapter<BigInteger>
              1. 在这一点,你发现在4.0里没有了Channel.isWritable()或者channelInterestChanged()。作为代替,你自己来管理那些未决定的写操作。新的sendNumbers()看起来如下:
              01private void sendNumbers() {
              02    // Do not send more than 4096 numbers.
              03    boolean finished = false;
              04    MessageBuf<Object> out = ctx.nextOutboundMessageBuffer();
              05    while (out.size() < 4096) {
              06        if (i <= count) {
              07            out.add(Integer.valueOf(i));
              08            i ++;
              09        else {
              10            finished = true;
              11            break;
              12        }
              13    }
              14 
              15    ChannelFuture f = ctx.flush();
              16    if (!finished) {
              17        f.addListener(numberSender);
              18    }
              19}
              20 
              21private final ChannelFutureListener numberSender = new ChannelFutureListener() {
              22    @Override
              23    public void operationComplete(ChannelFuture future) throws Exception {
              24        if (future.isSuccess()) {
              25            sendNumbers();
              26        }
              27    }
              28};
  评论这张
 
阅读(823)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017