Netty源码解读------------ServerBootstrap的启动(一)

来源:互联网 发布:form表单转换成json 编辑:程序博客网 时间:2024/05/16 15:50

在阅读Netty源码之前,务必要学习nio的知识,否则很难理解。

自jdk1.4自后,便引入了nio的类库。为了提高nio的系统性能以及吞吐量,有人就在其基础上再次进行封装,便出了Netty框架。现在不少问nio的技术面试官,大部分会问到你用过Netty框架吗?读过它的源码吗?由此,我便尝试着解读其源码,一起和大家分享,^__^。

  • Netty主要类
    • ServerBootstrap
    • NioServerSocketChannelFactory
    • NioWorker
    • PipeFactorySinkeFactory
    • DefaultChannelPipeline
    • Binder
    • NioServerSocketPipelineSink
    • NioServerSocketChannel

1. 首先分析它是如何启动监听的

package com.netty.test;  import org.jboss.netty.bootstrap.ServerBootstrap;  import org.jboss.netty.channel.*;  import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;  import org.jboss.netty.handler.codec.string.StringDecoder;  import org.jboss.netty.handler.codec.string.StringEncoder;  import java.net.InetSocketAddress;  import java.util.concurrent.Executors;  /**  * God Bless You!  * Author: Fangniude  * Date: 2013-07-15  */  public class NettyServer {      public static void main(String[] args) {          ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));          // Set up the default event pipeline.          bootstrap.setPipelineFactory(new ChannelPipelineFactory() {              public ChannelPipeline getPipeline() throws Exception {                  return Channels.pipeline(new StringDecoder(), new StringEncoder(), new ServerHandler());              }          });          // Bind and start to accept incoming connections.          Channel bind = bootstrap.bind(new InetSocketAddress(8000));          System.out.println("Server已经启动,监听端口: " + bind.getLocalAddress() + ", 等待客户端注册。。。");      }      private static class ServerHandler extends SimpleChannelHandler {         @Override          public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {              if (e.getMessage() instanceof String) {                String message = (String) e.getMessage();                  System.out.println("Client发来:" + message);                  e.getChannel().write("Server已收到刚发送的:" + message);                  System.out.println("\n等待客户端输入。。。");              }              super.messageReceived(ctx, e);          }          @Override          public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {              super.exceptionCaught(ctx, e);          }          @Override          public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {              System.out.println("有一个客户端注册上来了。。。");              System.out.println("Client:" + e.getChannel().getRemoteAddress());              System.out.println("Server:" + e.getChannel().getLocalAddress());              System.out.println("\n等待客户端输入。。。");              super.channelConnected(ctx, e);          }      }  } 

上面这段代码是启动服务器端的代码。
在ServerBootstrap里面bind方法是这样写的。

 public Channel bind(final SocketAddress localAddress) {        if (localAddress == null) {            throw new NullPointerException("localAddress");        }        //存储被注册的channel队列        final BlockingQueue<ChannelFuture> futureQueue =            new LinkedBlockingQueue<ChannelFuture>();        //这是一个解析触发事件 实现了SimpleChannelUpstreamHandler        ChannelHandler binder = new Binder(localAddress, futureQueue);        //默认是空        ChannelHandler parentHandler = getParentHandler();        //存储事件和触发事件的对象        ChannelPipeline bossPipeline = pipeline();        bossPipeline.addLast("binder", binder);        if (parentHandler != null) {            bossPipeline.addLast("userHandler", parentHandler);        }        //通过ChannelFactory创建一个ServerSocketChannel对象        Channel channel = getFactory().newChannel(bossPipeline);        // Wait until the future is available.        ChannelFuture future = null;        boolean interrupted = false;        do {            try {                //获取NioServerSocketChannel对象                future = futureQueue.poll(Integer.MAX_VALUE, TimeUnit.SECONDS);            } catch (InterruptedException e) {                interrupted = true;            }        } while (future == null);        if (interrupted) {            Thread.currentThread().interrupt();        }        // Wait for the future.        future.awaitUninterruptibly();        if (!future.isSuccess()) {            future.getChannel().close().awaitUninterruptibly();            throw new ChannelException("Failed to bind to: " + localAddress, future.getCause());        }        return channel;    }

下面看下 Channel channel = getFactory().newChannel(bossPipeline); 里面的写法。

 NioServerSocketChannel(            ChannelFactory factory,            ChannelPipeline pipeline,            ChannelSink sink) {        super(factory, pipeline, sink);        try {            socket = ServerSocketChannel.open();        } catch (IOException e) {            throw new ChannelException(                    "Failed to open a server socket.", e);        }        try {            socket.configureBlocking(false);        } catch (IOException e) {            try {                socket.close();            } catch (IOException e2) {                logger.warn(                        "Failed to close a partially initialized socket.", e2);            }            throw new ChannelException("Failed to enter non-blocking mode.", e);        }        config = new DefaultServerSocketChannelConfig(socket.socket());        //注意这里, 这里是触发打开事件, 看这个里面的实现        fireChannelOpen(this);    }
        /**     * Sends a {@code "channelOpen"} event to the first     * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of     * the specified {@link Channel}.  If the specified channel has a parent,     * a {@code "childChannelOpen"} event will be sent, too.     */    public static void fireChannelOpen(Channel channel) {        // Notify the parent handler.        if (channel.getParent() != null) {            fireChildChannelStateChanged(channel.getParent(), channel);        }        //这个pipeline就是之前在ServerBootstrap放进去的DefaultPipeLine对象,当时放了2个handler进去了。 sendUpStream则是取出向上去取里面的handler对象, 然后做处理.这里触发的是OPEN事件,发的是TRUE值,后面会用到。        channel.getPipeline().sendUpstream(                new UpstreamChannelStateEvent(                        channel, ChannelState.OPEN, Boolean.TRUE));    }void sendUpstream(DefaultChannelHandlerContext ctx, ChannelEvent e) {        try {            //看handlerUpstream代码            ((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e);        } catch (Throwable t) {            notifyHandlerException(e, t);        }    }
/**     * {@inheritDoc}  Down-casts the received upstream event into more     * meaningful sub-type event and calls an appropriate handler method with     * the down-casted event.     */    public void handleUpstream(            ChannelHandlerContext ctx, ChannelEvent e) throws Exception {        if (e instanceof MessageEvent) {            messageReceived(ctx, (MessageEvent) e);        } else if (e instanceof WriteCompletionEvent) {            WriteCompletionEvent evt = (WriteCompletionEvent) e;            writeComplete(ctx, evt);        } else if (e instanceof ChildChannelStateEvent) {            ChildChannelStateEvent evt = (ChildChannelStateEvent) e;            if (evt.getChildChannel().isOpen()) {                childChannelOpen(ctx, evt);            } else {                childChannelClosed(ctx, evt);            }        } else if (e instanceof ChannelStateEvent) {            ChannelStateEvent evt = (ChannelStateEvent) e;            switch (evt.getState()) {            case OPEN:                //发送的是OPEN事件,触发这里。                if (Boolean.TRUE.equals(evt.getValue())) {                    //Binder类里面的方法                    channelOpen(ctx, evt);                } else {                    channelClosed(ctx, evt);                }                break;            case BOUND:                if (evt.getValue() != null) {                    channelBound(ctx, evt);                } else {                    channelUnbound(ctx, evt);                }                break;            case CONNECTED:                if (evt.getValue() != null) {                    channelConnected(ctx, evt);                } else {                    channelDisconnected(ctx, evt);                }                break;            case INTEREST_OPS:                channelInterestChanged(ctx, evt);                break;            default:                ctx.sendUpstream(e);            }        } else if (e instanceof ExceptionEvent) {            exceptionCaught(ctx, (ExceptionEvent) e);        } else {            ctx.sendUpstream(e);        }    }
 private final class Binder extends SimpleChannelUpstreamHandler {        private final SocketAddress localAddress;        private final BlockingQueue<ChannelFuture> futureQueue;        private final Map<String, Object> childOptions =            new HashMap<String, Object>();        Binder(SocketAddress localAddress, BlockingQueue<ChannelFuture> futureQueue) {            this.localAddress = localAddress;            this.futureQueue = futureQueue;        }        @Override        public void channelOpen(                ChannelHandlerContext ctx,                ChannelStateEvent evt) {            try {                evt.getChannel().getConfig().setPipelineFactory(getPipelineFactory());                // Split options into two categories: parent and child.                Map<String, Object> allOptions = getOptions();                Map<String, Object> parentOptions = new HashMap<String, Object>();                for (Entry<String, Object> e: allOptions.entrySet()) {                    if (e.getKey().startsWith("child.")) {                        childOptions.put(                                e.getKey().substring(6),                                e.getValue());                    } else if (!e.getKey().equals("pipelineFactory")) {                        parentOptions.put(e.getKey(), e.getValue());                    }                }                // Apply parent options.                evt.getChannel().getConfig().setOptions(parentOptions);            } finally {                ctx.sendUpstream(evt);            }            //这里就是之前ServerBootstrap里面的futureQueue那个对象。存放了一个            boolean finished = futureQueue.offer(evt.getChannel().bind(localAddress));            assert finished;        }

下节将会讲解Netty的socket监听以及读取信息。

1 0
原创粉丝点击