网络编程与Netty(四) Netty源码-(Ⅶ)

Netty整体流程分析

​ 接下来就是Netty整体流程的源码讲解了,因为这部分内容十分的长,所以会分开多个小节来讲解。

//eventLoop暂时理解为线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
    //ServerBootStrap是启动必备的,启动相关的工作基本都是由它完成的
    ServerBootstrap sb = new ServerBootstrap();
    sb.group(group)
        .channel(NioServerSocketChannel.class)
        .localAddress(new InetSocketAddress(port))
        .childHandler(new ServerChannelInitializer());
    //bind()方法是整个服务启动的一个关键方法,并且同步
    ChannelFuture future = sb.bind().sync();
    future.channel().closeFuture().sync();
}finally {
    group.shutdownGracefully().sync();
}

​ 前面我们也写过一个Demo,基本上就这几行代码,就让我们的Netty跑起来并且实现了通信,那它背后都做了哪些事呢?接下来就以服务端启动为代表讲解下背后的流程:

​ 首先是实例化了EventLoopGroup和ServerBootStrap两个对象,EventLoopGroup前面一个章节已经讲过了,那么接下来重头戏自然就是ServerBootStrap,实例化出ServerBootStrap后就对实例进行各种配置,基本上就是简单地set,比较特别的一个点就是上面的channel(NioServerSocketChannel.class)方法,这里很明显,参数是一个class类型变量,Netty将通过反射产生这个类型的实例对象。

public B channel(Class<? extends C> channelClass) {
        if (channelClass == null) {
            throw new NullPointerException("channelClass");
        } else {
         //主要看ReflectiveChannelFactory(channelClass)这个类
            return this.channelFactory((io.netty.channel.ChannelFactory)(new ReflectiveChannelFactory(channelClass)));
        }
    }
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
  //这个就是channel()方法参数传进来的class对象,会通过构造函数存进来
    private final Class<? extends T> clazz;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        if (clazz == null) {
            throw new NullPointerException("clazz");
        } else {
           //将class对象放入成员变量clazz
            this.clazz = clazz;
        }
    }
//这个类主要看这个方法,看方法名就知道是实例化对象的方法
    public T newChannel() {
        try {
          //这个代码有玩过反射的读者肯定不陌生,就是通过反射实例化对象,然后return出去。
            return (Channel)this.clazz.getConstructor().newInstance();
        } catch (Throwable var2) {
            throw new ChannelException("Unable to create Channel from class " + this.clazz, var2);
        }
    }
    
    public String toString() {
        return StringUtil.simpleClassName(this.clazz) + ".class";
    }
}

​ 对ServerBootstrap实例对象进行各种设置之后,Netty又做了什么?接下来就到了最重要的一个方法——bind(),这个方法是整个服务端启动的根源地。

public ChannelFuture bind() {
    //先进行一系列校验
        this.validate();
        SocketAddress localAddress = this.localAddress;
        if (localAddress == null) {
            throw new IllegalStateException("localAddress not set");
        } else {
          //最关键的就是doBind()方法
            return this.doBind(localAddress);
        }
    }
private ChannelFuture doBind(final SocketAddress localAddress) {
    //这个方法是对Channel的创建new、初始化init和注册Register
        final ChannelFuture regFuture = this.initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        } else if (regFuture.isDone()) {
            ChannelPromise promise = channel.newPromise();
         //接下来看这个doBind0()方法,主要是进行绑定
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        promise.setFailure(cause);
                    } else {
                        promise.registered();
                        AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }

​ doBind方法中,主要是initAndRegister和doBind0两个方法。首先就是initAndRegister这个方法:

final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
          //这个方法熟悉不?在前面讲解AbstractBootstrap.channel()方法时就讲到了
          //newChannel是通过反射的方式创建了一个channel实例,这里是创建一个NioServerSocketChannel
          //所以进入到NioServerSocketChannel的构造函数看看
            channel = this.channelFactory.newChannel();
          //初始化刚生成的NioServerSocketChannel,主要是将参数配置加入到channel,并且加入handler
            this.init(channel);
        } catch (Throwable var3) {
            if (channel != null) {
                channel.unsafe().closeForcibly();
                return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
            }
            return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);
        }
    //这里进行注册register,将channel注册到eventLoop中
        ChannelFuture regFuture = this.config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
        return regFuture;
    }
private static java.nio.channels.ServerSocketChannel newSocket(SelectorProvider provider) {
    try {
      //生成一个JDK 中的 ServerSocketChannel
        return provider.openServerSocketChannel();
    } catch (IOException var2) {
        throw new ChannelException("Failed to open a server socket.", var2);
    }
}
public NioServerSocketChannel() {
  //调用上面的newSocket方法,参数就是一个JDK中的ServerSocketChannel
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

public NioServerSocketChannel(SelectorProvider provider) {
	this(newSocket(provider));
}

public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
  //channel是一个ServerSocketChannel
  //可以看到这里传入了一个16表示当前channel将会对accept事件感兴趣
    super((Channel)null, channel, 16);
    this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this,this.javaChannel().socket());
}

​ 接着往上层父类中看,来到AbstractNioChannel这个类:

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent);
  //ch是ServerSocketChannel
    this.ch = ch;
  //这个就是16,也就是accept事件
    this.readInterestOp = readInterestOp;

    try {
      //这里将通道设置为非阻塞的
        ch.configureBlocking(false);
    } catch (IOException var7) {
        try {
            ch.close();
        } catch (IOException var6) {
            if (logger.isWarnEnabled()) {
                logger.warn("Failed to close a partially initialized socket.", var6);
            }
        }
        throw new ChannelException("Failed to enter non-blocking mode.", var7);
    }
}

​ 继续往上层父类构造函数看:

protected AbstractChannel(Channel parent) {
        this.parent = parent;
        this.id = this.newId();
        this.unsafe = this.newUnsafe();
   	//在这里创建出来了ChannelPipeline,其实是个DefaultChannelPipeline,看下面的方法就知道了
        this.pipeline = this.newChannelPipeline();
    }

protected DefaultChannelPipeline newChannelPipeline() {
   	//接下来就继续看看这个构造方法
        return new DefaultChannelPipeline(this);
    }

protected DefaultChannelPipeline(Channel channel) {
        this.channel = (Channel)ObjectUtil.checkNotNull(channel, "channel");
        this.succeededFuture = new SucceededChannelFuture(channel, (EventExecutor)null);
        this.voidPromise = new VoidChannelPromise(channel, true);
    //pipeline默认创建了两个handler,下面四行代码,就是初始化了tail和head,然后将他们形成双向链表
        this.tail = new DefaultChannelPipeline.TailContext(this);
        this.head = new DefaultChannelPipeline.HeadContext(this);
        this.head.next = this.tail;
        this.tail.prev = this.head;
    }
//从HeadContext的类声明可以看出,HeadContext既是ChannelHandlerContext又是出站和入站Handler
final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {
    
}

//从TailContext的类声明可以看出,TailContext既是ChannelHandlerContext又是入站Handler
final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {

}

​ 在DefaultChannelPipeline中有很多关于ChannelHandlerContext加入到pipeline中的方法,这里找一个addFirst0方法:其它的也是类似的

private void addFirst0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext nextCtx = this.head.next;
        newCtx.prev = this.head;
        newCtx.next = nextCtx;
        this.head.next = newCtx;
        nextCtx.prev = newCtx;
    }

​ 这些方法结合上面HeadContext和TailContext的声明,可以得出结论我们增加的任何自定义 handler,一定是放在 TailContext 和 HeadContext 之间,HeadContext 一定是入站的第一个 Handler 和出站的最后一个 Handler,TailContext 是入站的最后一个 Handler。到这里,newChannel()执行完成了,一个NioServerSocketChannel 的实例被创建了。

​ 接下来执行 init(channel),init()是一个抽象方法,实际上调用的是ServerBootStrap中的实现:

void init(Channel channel) throws Exception {
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }
	//先会设置各种相关参数
        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }
	//拿到channel中的pipeline
        ChannelPipeline p = channel.pipeline();
	//这里是拿到子channel的一些参数
        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
        }
	//往主Channel(也就是NIoServerSocketChannel)中的pipeline加入一个ChannelInitializer,这个类继承自ChannelInboundHandlerAdapter
    //ChannelInitializer这个类的主要任务在initChannel方法,这个方法惨数是前面newChannel生成的主channel,也就是NIoServerSocketChannel
    //将主channel传进去,然后在里面给主channel中的pipeline添加handler
    //实际上这个initChannel()方法需要在pipeline.invokeHandlerAddedIfNeeded()被调用时才会执行,前面有提到过,这里不赘述
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
              //这个获取的是ServerBootStrap。handler()中加入的handler,而不是childHandler()中的handler
              //因为我们代码中没写ServerBootStrap.handler()方法,所以这里为null
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }
			 //这里是比较关键的地方,它调用主channel绑定的EventLoop中的execute方法来执行一个Runnable
              //这个Runnable里面的run方法就是加入了一个处理客户端新连接的Handler----ServerBootstrapAcceptor
              //所以接下来主要看EventLoop中的execute方法和ServerBootstrapAcceptor这个Handler
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

​ 先看下EventLoop中的execute方法:

public void execute(Runnable task) {
    //首先判断Runnable是否为null
        if (task == null) {
            throw new NullPointerException("task");
        }
	//这里判断执行execute的线程是否为EventLoop中的线程
        boolean inEventLoop = inEventLoop();
    //处理task
        addTask(task);
    //重点在这里,如果上面的判断为false 
        if (!inEventLoop) {
            //这个方法里开启一个线程赋值到当前的EventLoop中
            startThread();
            if (isShutdown() && removeTask(task)) {
                reject();
            }
        }

        if (!addTaskWakesUp && wakesUpForTask(task)) {
            wakeup(inEventLoop);
        }
    }
private void startThread() {
        if (state == ST_NOT_STARTED) {
            if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
                try {
                  //来到这个方法,开启一个线程
                    doStartThread();
                } catch (Throwable cause) {
                    STATE_UPDATER.set(this, ST_NOT_STARTED);
                    PlatformDependent.throwException(cause);
                }
            }
        }
    }



private void doStartThread() {
    //断言当前EventLoop的线程是null,如果不为空则抛出异常
        assert thread == null;
    //这里会调用executor.execute()方法,这个executor在前面EventLoop系列源码解析中的MultithreadEventExecutorGroup构造函数中说过
    //他是一个ThreadPerTaskExecutor类型,所以进入到ThreadPerTaskExecutor的execute方法看看
        executor.execute(new Runnable() {
            @Override
            public void run() {
                //现在处于一个new Runnable中,所以thread.currentThread现在是一个新的线程,然后赋值到EventLoop的thread属性
                thread = Thread.currentThread();
                if (interrupted) {
                    thread.interrupt();
                }

                boolean success = false;
                updateLastExecutionTime();
                try {
                  //这个方法应该都很熟悉了,eventLoop.run(),在讲解EventLoop源码系列那一节就说到了这个方法,不记得的可以回去看看
                  //大致的执行一个循环遍历事件选择器selector的过程,从这个选择器中不断的拿出事件,然后处理的过程,这里就不赘述了。
                    SingleThreadEventExecutor.this.run();
                    success = true;
                } catch (Throwable t) {
                    logger.warn("Unexpected exception from an event executor: ", t);
                } finally {
                    for (;;) {
                        int oldState = state;
                        if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
                                SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
                            break;
                        }
                    }
                    // Check if confirmShutdown() was called at the end of the loop.
                    if (success && gracefulShutdownStartTime == 0) {
                        if (logger.isErrorEnabled()) {
                            logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
                                    SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
                                    "be called before run() implementation terminates.");
                        }
                    }
                    try {
                        // Run all remaining tasks and shutdown hooks.
                        for (;;) {
                            if (confirmShutdown()) {
                                break;
                            }
                        }
                    } finally {
                        try {
                            cleanup();
                        } finally {
                            STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
                            threadLock.release();
                            if (!taskQueue.isEmpty()) {
                                if (logger.isWarnEnabled()) {
                                    logger.warn("An event executor terminated with " +
                                            "non-empty task queue (" + taskQueue.size() + ')');
                                }
                            }
                            terminationFuture.setSuccess(null);
                        }
                    }
                }
            }
        });
    }
public void execute(Runnable command) {
     //主要就是新启一个线程,然后传递到Runnable实例中,也就是上面的Thread.currentThread();所获取到的线程就是这里新启的线程
        threadFactory.newThread(command).start();
    }

​ 接着来看ServerBootstrapAcceptor,这个handler主要处理客户端新连接,

//它是 ServerBootstrap 的内部类,并且处理入站事件,主要重写了 channelRead 方法和 exceptionCaught 方法。
private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
    
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        //前面笔者在Unsafe系列源码的NioMessageUnsafe.read()方法讲解中,说到了ServerBootstrapAcceptor.channelRead方法()
        //这个msg是一个子Channel,具体怎么来的Channel,在前面NioMessageUnsafe.read()方法有详细的讲解,这里不赘述
            final Channel child = (Channel) msg;
        //拿到了子channel后就对它进行一些属性配置的赋值,例如childHandler(),option()等设置的属性配置
            child.pipeline().addLast(childHandler);
            setChannelOptions(child, childOptions, logger);
            for (Entry<AttributeKey<?>, Object> e: childAttrs) {
                child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
            }
            try {
              //属性值set完后,就需要将子channel注册到EventLoop中,且与Selector挂钩关注某种事件
              //具体的注册过程与马上就要讲的主channelregister是一样的,所以这里不赘述
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }
}

​ 将这个handler加入到主channel的pipeline后,主channel的pipeline上就有三个handler:HeadContext(入/出) -> ServerBootstrapAcceptor(入) -> TailContext(入)。

​ 至此init()方法执行完成,主channel初始化完成。接下来将主channel与EventLoop关联起来(子Channel也是一样的),config().group().register(channel)方法,这个方法是抽象方法,最终调用会来到MultithreadEventLoopGroup 的 register(Channel channel)方法:

public ChannelFuture register(Channel channel) {
    //这个next()方法实际上就是在group中选择一个EventLoop,然后调用其register方法将channel注册进去。
        return next().register(channel);
    }
public ChannelFuture register(Channel channel) {
    //调用下面的register
        return register(new DefaultChannelPromise(channel, this));
    }

public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
    //实际上调用的是AbstractUnsafe的 register 方法,进到这个方法看看,注意参数this是将当前被选中的eventLoop作为参数传入
    //AbstractUnsafe的register是前面在Unsafe源码里专门讲过的
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            if (eventLoop == null) {
                throw new NullPointerException("eventLoop");
            } else if (AbstractChannel.this.isRegistered()) {
                promise.setFailure(new IllegalStateException("registered to an event loop already"));
            } else if (!AbstractChannel.this.isCompatible(eventLoop)) {
                promise.setFailure(new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
            } else {
              //前面一堆的逻辑都是在做校验,如果校验通过了就会来到这个代码块
              //这里首先将当前的Channel与参数中的EventLoop建立关系
                AbstractChannel.this.eventLoop = eventLoop;
            //这个首先进行线程的本地性校验,也就是前面说过得,校验现在执行的线程是不是与Channel关联
            //的EventLoop中的线程,如果是则直接执行register0方法,如果不是则调用EventLoop.execute来执行
            //最终不管走哪里都是执行register0方法,所以接下来进入register0方法
                if (eventLoop.inEventLoop()) {
                    this.register0(promise);
                } else {
                    try {
                     //eventLoop.execute()方法前面讲解主channel的init()方法时已经详细讲过,就不赘述了
                        eventLoop.execute(new Runnable() {
                            public void run() {
                                AbstractUnsafe.this.register0(promise);
                            }
                        });
                    } catch (Throwable var4) {
                        AbstractChannel.logger.warn("Force-closing a channel whose registration task was not accepted by an event loop: {}", AbstractChannel.this, var4);
                        this.closeForcibly();
                        AbstractChannel.this.closeFuture.setClosed();
                        this.safeSetFailure(promise, var4);
                    }
                }
            }
        }
private void register0(ChannelPromise promise) {
            try {
                if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = this.neverRegistered;
                //调用doRegister方法,这个方法说了很多次了吧,大概就是将Channel注册到EventLoop中的
                //Selector选择器中,但是此时还未将关注的事件注册进去。
                AbstractChannel.this.doRegister();
                this.neverRegistered = false;
                AbstractChannel.this.registered = true;
             //执行ChannelInitializer.initChannel,以保证handler被添加到pipeline上。
             //现在看到这个应该能想起前面的主channel中的pipeline中加入了一个ChannelInitializer并重写了initChannel方法,就是此时被调用的
                AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();
                this.safeSetSuccess(promise);
             //触发了ChannelRegistered事件,跟ChannelActive作用一样都是在某个特定时间点执行
                AbstractChannel.this.pipeline.fireChannelRegistered();
                if (AbstractChannel.this.isActive()) {
                    if (firstRegistration) {
                //如果Channel处于活动状态且是第一次注册,则触发ChannelActive事件。
                //为什么要判断第一次呢?因为可能是之前register然后deregister了,现在有register的
                //防止多次触发ChannelActive事件
                        AbstractChannel.this.pipeline.fireChannelActive();
                    } else if (AbstractChannel.this.config().isAutoRead()) {
            //如果Channel处于活动状态且不是第一次注册,并设置了AutoRead,则调用beginRead
            //beginRead最重要的就是doBeginRead方法,这个之前讲过,就是将Channel关注的事件注册到Selector
                        this.beginRead();
                    }
                }
            } catch (Throwable var3) {
                this.closeForcibly();
                AbstractChannel.this.closeFuture.setClosed();
                this.safeSetFailure(promise, var3);
            }
        }

​ 到这里,initAndRegister()方法的主要工作就做完了,这只是doBind()的一步,doBind()方法里还有调用了一个很重要的方法doBind0()方法,这个下个小节继续讲解。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值