7-网络架构和Netty系列-Bootstrap运行原理分析

Bootstrap运行原理分析

NioSocketChannel初始化

(1)调用NioSocketChannel.newSocket(DEFAULT_SELECTOR_PROVIDER)打开一个新的JavaNioSocketChannel。

(2)初始化AbstractChannel(Channel parent)对象并给属性赋值,具体赋值的属性如下。

● id:每个Channel都会被分配一个唯一的id。

● parent:属性值默认为null。

● unsafe:通过调用newUnsafe()方法实例化一个Unsafe对象,它的类型是AbstractNioByteChannel.NioByteUnsafe内部类。

● pipeline:是通过调用new DefaultChannelPipeline(this)新创建的实例。

(3)AbstractNIOChannel中被赋值的属性如下。

● ch:被赋值为Java原生SocketChannel,即NioSocketChannel的newSocket()方法返回的Java NIO SocketChannel。

● readInterestOp:被赋值为SelectionKey.OP_READ。

● ch:被配置为非阻塞,即调用ch.configureBlocking(false)方法。

(4)NioSocketChannel中被赋值的属性:config=new NioSocketChannelConfig(this,socket.socket())。

Unsafe初始化

Unsafe其实是对Java底层Socket操作的封装,它实际上是沟通Netty上层和Java底层的重要桥梁。

在这里插入图片描述

在实例化的NioSocketChannel中的Unsafe属性其实是一个NioSocketChannelUnsafe的实例。

		//AbstractChannel.java 
		//构造函数
    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        unsafe = newUnsafe();
        pipeline = new DefaultChannelPipeline(this);
    }
		protected abstract AbstractUnsafe newUnsafe();
    //NioSocketChannel.java
    protected AbstractNioUnsafe newUnsafe() {
        return new NioSocketChannelUnsafe();
    }

ChannelPipeline的初始化

//NioSocketChannel或者NioServerSocketChannel#的多级父类中AbstractChannel中初始化Channel时,实例化了一个ChannelPipeline
    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        unsafe = newUnsafe();
        pipeline = new DefaultChannelPipeline(this);
    }

在实例化一个Channel时,必然都要实例化一个ChannelPipeline。而我们确实在AbstractChannel的构造器中看到了Pipeline属性被初始化为DefaultChannelPipeline的实例

//DefaultChannelPipeline的构造器需要传入一个Channel,而这个Channel其实就是我们实例化的NioSocketChannel对象
public DefaultChannelPipeline(AbstractChannel channel) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
//  DefaultChannelPipeline会将这个NioSocketChannel对象保存在Channel属性中
        this.channel = channel;
//这两个属性是双向链表的头和尾。其实在DefaultChannelPipeline中维护了一个以AbstractChannelHandlerContext为节点元素的双向链表,这个链表是Netty实现Pipeline机制的关键
        tail = new TailContext(this);
        head = new HeadContext(this);

        head.next = tail;
        tail.prev = head;
    }

链表中Head是一个ChannelOutboundHandler,而Tail则是一个ChannelInboundHandler

//一个特殊的包罗万象的处理程序,可以处理字节和消息。
//TailContext
static final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
}
//HeadContext
static final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler {
}

EventLoop的初始化

public class NioEventLoopGroup extends MultithreadEventLoopGroup {
    //Netty首先从系统属性中获取“io.netty.eventLoopThreads”的值,如果我们没有设置,就返回默认值,即CPU核数×2
		public NioEventLoopGroup(int nThreads) {
        this(nThreads, null);
    }
}

public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
}

public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
		//创建一个大小为nThreads的SingleThreadEventExecutor数组。
    private final EventExecutor[] children;
    private final AtomicInteger childIndex = new AtomicInteger();
    private final AtomicInteger terminatedChildren = new AtomicInteger();
    private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    private final EventExecutorChooser chooser;
}
MultithreadEventExecutorGroup处理逻辑

(1)创建一个大小为nThreads的SingleThreadEventExecutor数组。

(2)根据nThreads的大小,创建不同的Chooser,即如果nThreads是2的平方,则使用PowerOfTwoEventExecutorChooser,反之使用GenericEventExecutorChooser。不论使用哪个Chooser,它们的功能都是一样的,即从children数组中选出一个合适的EventExecutor实例。

(3)调用newChild()方法初始化children数组。

EventLoopGroup的初始化过程

(1)EventLoopGroup(其实是MultithreadEventExecutorGroup)内部维护一个类型为EventExecutor的children数组,其大小是nThreads,这样就构成了一个线程池。

(2)我们在实例化NioEventLoopGroup时,如果指定线程池大小,则nThreads就是指定的值,反之是CPU核数×2。

(3)在MultithreadEventExecutorGroup中调用newChild()象方法来初始化children数组。

(4)newChild()方法是在NioEventLoopGroup中实现的,它返回一个NioEventLoop实例。

(5)初始化NioEventLoop对象并给属性赋值,具体赋值的属性如下。

● provider:就是在NioEventLoopGroup构造器中,调用SelectorProvider.provider()方法获取的SelectorProvider对象。

● selector:就是在NioEventLoop构造器中,调用provider.openSelector()方法获取的Selector对象。

将Channel注册到Selector

ChannelFuture regFuture = initAndRegister();
ChannelFuture initAndRegister() {
    Channel channel = channelFactory().newChannel();
	  ChannelFuture regFuture = group().register(channel);
  	return regFuture;
}

AbstractBootstrap的initAndRegister()方法中调用的是Unsafe的register()方法,接下来看一下AbstractChannel$AbstractUnsafe.register()方法的具体实现代码

        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
          AbstractChannel.this.eventLoop = eventLoop;
                    this.register0(promise);
        }

private void register0(ChannelPromise promise) {
            try {
                if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = this.neverRegistered;
                //register0()方法又调用了AbstractNioChannel的doRegister()方法
                AbstractChannel.this.doRegister();
                this.neverRegistered = false;
                AbstractChannel.this.registered = true;
                this.safeSetSuccess(promise);
                //Channel已注册到EventLoop
                AbstractChannel.this.pipeline.fireChannelRegistered();
                if (firstRegistration && AbstractChannel.this.isActive()) {
                		//现在处于活动状态,表示已连接
                    AbstractChannel.this.pipeline.fireChannelActive();
                }
            } catch (Throwable var3) {
                this.closeForcibly();
                AbstractChannel.this.closeFuture.setClosed();
                this.safeSetFailure(promise, var3);
            }
}

public abstract class AbstractNioChannel extends AbstractChannel {
    @Override
    protected void doRegister() throws Exception {
        //这里我们将SocketChannel注册到与eventLoop关联的Selector上
        selectionKey = javaChannel().register(eventLoop().selector, 0, this);
    }
}

Channel的注册过程

(1)在AbstractBootstrap的initAndRegister()方法中,通过group().register(channel)调用MultithreadEventLoopGroup的register()方法。
(2)在MultithreadEventLoopGroup的register()方法中,调用next()方法获取一个可用的SingleThreadEventLoop,然后调用它的register()方法。
(3)在SingleThreadEventLoop的register()方法中,调用channel.unsafe().register(this,promise)方法获取Channel的unsafe()底层操作对象,然后调用Unsafe的register()方法。
(4)在AbstractUnsafe的register()方法中,调用register0()方法注册Channel对象。
(5)在AbstractUnsafe的register0()方法中,调用AbstractNioChannel的doRegister()方法。
(6)AbstractNioChannel的doRegister()方法通过javaChannel().register(eventLoop().selector,0,this)将Channel对应的Java NIO的SocketChannel注册到一个eventLoop的Selector中,并且将当前Channel作为Attachment与SocketChannel关联。

Handler的添加过程

Netty有一个强大和灵活之处就是基于Pipeline的自定义Handler机制

	bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .remoteAddress(HOST, PORT)
                //传入的参数是一个派生于抽象类ChannelInitializer的匿名类,它也实现了ChannelHandler接口
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
                    }
                });

public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
    public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
				//在channelRegistered()方法中,会调用initChannel()方法,将自定义的Handler添加到ChannelPipeline中
      	initChannel((C) ctx.channel());
        //将自己从ChannelPipeline中删除
        ctx.pipeline().remove(this);
        ctx.fireChannelRegistered();
    }
}

客户端发起连接请求

public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
private ChannelFuture doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        final ChannelPromise promise = channel.newPromise();
        if (regFuture.isDone()) {
            doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
        } else {
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
                }
            });
        }

        return promise;
    }

    private static void doConnect0(
            final ChannelFuture regFuture, final Channel channel,
            final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {

        // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
        // the pipeline in its channelRegistered() implementation.
        channel.eventLoop().execute(new Runnable() {
......
//                      eventLoop线程会调用Channel的connect()方法
                        channel.connect(remoteAddress, localAddress, promise);
......
        });
    }
  
}

继续跟踪channel.connect()方法,我们发现它调用的是DefaultChannelPipeline的connect()方法

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    @Override
    public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
        return pipeline.connect(remoteAddress, promise);
    }
}

Tail是一个TailContext的实例,而TailContext又是AbstractChannelHandlerContext的子类,并且没有实现connect()方法,因此这里调用的其实是AbstractChannelHandlerContext的connect()方法

final class DefaultChannelPipeline implements ChannelPipeline {
    @Override
    public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
        return tail.connect(remoteAddress, promise);
    }
}
@Override
public ChannelFuture connect(
        final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {

    if (remoteAddress == null) {
        throw new NullPointerException("remoteAddress");
    }
    if (isNotValidPromise(promise, false)) {
        // cancelled
        return promise;
    }
//从DefaultChannelPipeline内的双向链表的Tail开始,不断向前找到第一个Outbound为true的AbstractChannelHandlerContext,
    final AbstractChannelHandlerContext next = findContextOutbound();
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
//      然后调用它的invokeConnect()方法
        next.invokeConnect(remoteAddress, localAddress, promise);
    } else {
        safeExecute(executor, new Runnable() {
            @Override
            public void run() {
                next.invokeConnect(remoteAddress, localAddress, promise);
            }
        }, promise, null);
    }
    return promise;
}

    private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.prev;
        } while (!ctx.outbound);
        return ctx;
    }

    private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
        if (invokeHandler()) {
            try {
              //这里调用的是ChannelOutboundHandler的connect ,实际调用的是DefaultChannelPipeline的connect
                ((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise);
            } catch (Throwable t) {
                notifyOutboundHandlerException(t, promise);
            }
        } else {
            connect(remoteAddress, localAddress, promise);
        }
    }

final class DefaultChannelPipeline implements ChannelPipeline {
        @Override
        public void connect(
                ChannelHandlerContext ctx,
                SocketAddress remoteAddress, SocketAddress localAddress,
                ChannelPromise promise) throws Exception {
          //调用AbstractNioChannel的connect方法
            unsafe.connect(remoteAddress, localAddress, promise);
        }
}


public abstract class AbstractNioChannel extends AbstractChannel {
public final void connect(
                final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
            ......
                //doConnect()方法是在NioSocketChannel中实现的,因此进入NioSocketChannel的doConnect()方法
                if (doConnect(remoteAddress, localAddress)) {
                    fulfillConnectPromise(promise, wasActive);
                } else {
                    ......
        }
}
public class NioSocketChannel extends AbstractNioByteChannel implements io.netty.channel.socket.SocketChannel {
@Override
    protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
        if (localAddress != null) {
            javaChannel().socket().bind(localAddress);
        }

        boolean success = false;
        try {
        //获取Java NIO的SocketChannel,然后获取NioSocketChannel的newSocket()方法返回的SocketChannel对象;再调用SocketChannel的connect()方法完成Java NIO底层的Socket连接
						boolean connected = javaChannel().connect(remoteAddress);
            if (!connected) {
                selectionKey().interestOps(SelectionKey.OP_CONNECT);
            }
            success = true;
            return connected;
        } finally {
            if (!success) {
                doClose();
            }
        }
    }
}        

总结流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xianghan收藏册

极简精品作,一分也是一份鼓励哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值