Netty4学习笔记(3)-- ServerBootstrap

来源:互联网 发布:vb编程软件中文下载 编辑:程序博客网 时间:2024/05/18 08:24

转自:http://blog.csdn.net/zxhoo/article/details/17532857

这篇文章接着上一篇,分析一下Netty4的ServerBootstrp是如何工作的。

EchoServer

先看看Netty自带的EchoServer例子:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Echoes back any received data from a client. 
  3.  */  
  4. public class EchoServer {  
  5.   
  6.     private final int port;  
  7.   
  8.     public EchoServer(int port) {  
  9.         this.port = port;  
  10.     }  
  11.   
  12.     public void run() throws Exception {  
  13.         // Configure the server.  
  14.         EventLoopGroup bossGroup = new NioEventLoopGroup();  
  15.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
  16.         try {  
  17.             ServerBootstrap b = new ServerBootstrap();  
  18.             b.group(bossGroup, workerGroup)  
  19.              .channel(NioServerSocketChannel.class)  
  20.              .option(ChannelOption.SO_BACKLOG, 100)  
  21.              .handler(new LoggingHandler(LogLevel.INFO))  
  22.              .childHandler(new ChannelInitializer<SocketChannel>() {  
  23.                  @Override  
  24.                  public void initChannel(SocketChannel ch) throws Exception {  
  25.                      ch.pipeline().addLast(  
  26.                              //new LoggingHandler(LogLevel.INFO),  
  27.                              new EchoServerHandler());  
  28.                  }  
  29.              });  
  30.   
  31.             // Start the server.  
  32.             ChannelFuture f = b.bind(port).sync();  
  33.   
  34.             // Wait until the server socket is closed.  
  35.             f.channel().closeFuture().sync();  
  36.         } finally {  
  37.             // Shut down all event loops to terminate all threads.  
  38.             bossGroup.shutdownGracefully();  
  39.             workerGroup.shutdownGracefully();  
  40.         }  
  41.     }  
  42.   
  43.     public static void main(String[] args) throws Exception {  
  44.         int port;  
  45.         if (args.length > 0) {  
  46.             port = Integer.parseInt(args[0]);  
  47.         } else {  
  48.             port = 8080;  
  49.         }  
  50.         new EchoServer(port).run();  
  51.     }  
  52. }  
可以看出,用法和Bootstrap差不多。

作为Builder的ServerBootstrap

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public final class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {  
  2.   
  3.     private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();  
  4.     private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();  
  5.     private volatile EventLoopGroup childGroup;  
  6.     private volatile ChannelHandler childHandler;  
  7.     // ...  
  8. }  
看代码可以知道,ServerBootstrap比它的超类多了四个Part,如下图所示:

从bind()方法入手

bind()方法实际上是在AbstractBootstrap里定义的,bind()先调用validate()方法检查各个Part是否准备就绪,然后把工作交给了doBind()方法。doBind()方法首先调用initAndRegister()方法,然后把工作交给doBind0()。initAndRegister()会调用模板方法init()来初始化Channel,initAndRegister()方法的细节上篇文章分析过了,这里不再复述。下面是整个方法调用过程的示意图:


init()方法

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. void init(Channel channel) throws Exception {  
  3.     final Map<ChannelOption<?>, Object> options = options();  
  4.     synchronized (options) {  
  5.         channel.config().setOptions(options);  
  6.     }  
  7.   
  8.     final Map<AttributeKey<?>, Object> attrs = attrs();  
  9.     synchronized (attrs) {  
  10.         for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {  
  11.             @SuppressWarnings("unchecked")  
  12.             AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();  
  13.             channel.attr(key).set(e.getValue());  
  14.         }  
  15.     }  
  16.   
  17.     ChannelPipeline p = channel.pipeline();  
  18.     if (handler() != null) {  
  19.         p.addLast(handler());  
  20.     }  
  21.   
  22.     final EventLoopGroup currentChildGroup = childGroup;  
  23.     final ChannelHandler currentChildHandler = childHandler;  
  24.     final Entry<ChannelOption<?>, Object>[] currentChildOptions;  
  25.     final Entry<AttributeKey<?>, Object>[] currentChildAttrs;  
  26.     synchronized (childOptions) {  
  27.         currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));  
  28.     }  
  29.     synchronized (childAttrs) {  
  30.         currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));  
  31.     }  
  32.   
  33.     p.addLast(new ChannelInitializer<Channel>() {  
  34.         @Override  
  35.         public void initChannel(Channel ch) throws Exception {  
  36.             ch.pipeline().addLast(new ServerBootstrapAcceptor(  
  37.                     currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));  
  38.         }  
  39.     });  
  40. }  

ServerBootstrap类的init()方法虽然很长,但是却不难理解。首先是给Channel设置options和attrs,然后把User提供的针对NioServerSocketChannel的Handler添加到Pipeline的末尾。接下来复制childOptions和childAttrs,最后实例化一个ChannelInitializer,添加到Pipeline的末尾。init()方法执行完毕之后,AbstractBootstrap的initAndRegister()方法会将NioServerSocketChannel注册到group里。到此为止,NioServerSocketChannel的状态如下图所示:

ChannelInitializer在channelRegistered事件触发后会调用initChannel()方法,随后把自己从Pipeline里删除:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Sharable  
  2. public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {  
  3.   
  4.     private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class);  
  5.   
  6.     /** 
  7.      * This method will be called once the {@link Channel} was registered. After the method returns this instance 
  8.      * will be removed from the {@link ChannelPipeline} of the {@link Channel}. 
  9.      * 
  10.      * @param ch            the {@link Channel} which was registered. 
  11.      * @throws Exception    is thrown if an error occurs. In that case the {@link Channel} will be closed. 
  12.      */  
  13.     protected abstract void initChannel(C ch) throws Exception;  
  14.   
  15.     @SuppressWarnings("unchecked")  
  16.     @Override  
  17.     public final void channelRegistered(ChannelHandlerContext ctx)  
  18.             throws Exception {  
  19.         boolean removed = false;  
  20.         boolean success = false;  
  21.         try {  
  22.             initChannel((C) ctx.channel());  
  23.             ctx.pipeline().remove(this);  
  24.             removed = true;  
  25.             ctx.fireChannelRegistered();  
  26.             success = true;  
  27.         } catch (Throwable t) {  
  28.             logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);  
  29.         } finally {  
  30.             if (!removed) {  
  31.                 ctx.pipeline().remove(this);  
  32.             }  
  33.             if (!success) {  
  34.                 ctx.close();  
  35.             }  
  36.         }  
  37.     }  
  38. }  

所以注册之后的NioServerSocketChannel状态如下图所示:

ServerBootstrapAcceptor

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {  
  2.   
  3.     private final EventLoopGroup childGroup;  
  4.     private final ChannelHandler childHandler;  
  5.     private final Entry<ChannelOption<?>, Object>[] childOptions;  
  6.     private final Entry<AttributeKey<?>, Object>[] childAttrs;  
  7.   
  8.     @SuppressWarnings("unchecked")  
  9.     ServerBootstrapAcceptor(  
  10.             EventLoopGroup childGroup, ChannelHandler childHandler,  
  11.             Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs) {  
  12.         this.childGroup = childGroup;  
  13.         this.childHandler = childHandler;  
  14.         this.childOptions = childOptions;  
  15.         this.childAttrs = childAttrs;  
  16.     }  
  17.   
  18.     @Override  
  19.     @SuppressWarnings("unchecked")  
  20.     public void channelRead(ChannelHandlerContext ctx, Object msg) {  
  21.         Channel child = (Channel) msg;  
  22.   
  23.         child.pipeline().addLast(childHandler);  
  24.   
  25.         for (Entry<ChannelOption<?>, Object> e: childOptions) {  
  26.             try {  
  27.                 if (!child.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {  
  28.                     logger.warn("Unknown channel option: " + e);  
  29.                 }  
  30.             } catch (Throwable t) {  
  31.                 logger.warn("Failed to set a channel option: " + child, t);  
  32.             }  
  33.         }  
  34.   
  35.         for (Entry<AttributeKey<?>, Object> e: childAttrs) {  
  36.             child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());  
  37.         }  
  38.   
  39.         try {  
  40.             childGroup.register(child);  
  41.         } catch (Throwable t) {  
  42.             child.unsafe().closeForcibly();  
  43.             logger.warn("Failed to register an accepted channel: " + child, t);  
  44.         }  
  45.     }  
  46.     // ...  
  47. }  

ServerBootstrapAcceptor在channelRead事件触发的时候(也就有客户端连接的时候),把childHandler加到childChannel Pipeline的末尾,设置childHandler的options和attrs,最后把childHandler注册进childGroup,如下图所示:

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 我很懒不想工作怎么办 金寒水冷的八字怎么办 两岁宝宝内八字怎么办 小孩走路脚内八字怎么办 10岁走路内八字怎么办 8岁孩走路内八字怎么办 一岁宝宝足外翻怎么办 2岁宝宝小腿弯怎么办啊 一岁宝宝小腿弯怎么办 一岁小儿o型腿怎么办 两岁宝宝o型腿怎么办 狗狗前腿外八字怎么办 20岁走路内八字怎么办 9岁儿童脚内八字怎么办 5岁宝宝脚内八字怎么办 一岁宝宝内八字怎么办 两人八字合不合怎么办 考到不好的大学怎么办 考的大学不理想怎么办 只考上二本大学怎么办 w7电脑中病毒了怎么办 电脑中病毒了该怎么办 泰迪呼吸急促怎么办啊 狗狗呼吸急促是怎么办 狗狗着凉了呕吐怎么办 狗鼻子流黄鼻涕怎么办 刚出生婴儿睡觉不踏实怎么办 有人溺水后你该怎么办 借钱不还怎么办没欠条 私人欠货款不还怎么办 公司欠货款不还怎么办 两个人离婚一方不同意怎么办 比亚迪l3油耗高怎么办 u盘密码忘记了怎么办 主板没有m.2接口怎么办 点痣留下了疤怎么办 危险三角区长痘痘怎么办 挤了危险三角区怎么办 三角区长痘挤了怎么办 三角区发红长痘怎么办 激光祛斑碰水了怎么办