netty 源码解析一:ServerBootstrap 服务端

ServerBootstrap 服务启动类

结构: 继承 AbstractBootstrap 抽象类

使用案例:

	ServerBootstrap server = new ServerBootstrap();
	server.group(new NioEventLoopGroup(), new NioEventLoopGroup()); // EventLoopGroup接口
	server.channel(NioServerSocketChannel.class); // Channel.class类类型
	server.childHandler(new ChannelInitializer<Channel>(){ // ChannelHandler接口
		initChannel(Channel c){
			c.pipeline().addLast(new SimpleChannelInboundHandler<Object>(){ // ChannelHandler接口
				channelRead0(ChannelHandlerContext ctx, Object msg) // 发送消息
			});
		}
	});
	ChannelFutrue future = server.bind(8899).sync();
方法:group(EventLoopGroup) 配置线程池

group(EventLoopGroup, EventLoopGroup) 创建 NioEventLoopGroup 线程组(池). 为 ServerBootstrap 配置 childGroup 线程池, AbstractBootstrap 父类配置 group 线程池.
(这里暂时未讲解,一个线程池与二个线程池的区别)

方法:channel(Channel.class) 配置传输管道

注意, NioServerSocketChannel 是 NIO 的传输管道. 内部是封装 java.nio.channels.ServerSocketChannel 管道. 通过nio管道实现消息传输。

这里源码追踪: AbstractBootstrap 类中 channel 方法

	public B channel(Class<? extends C> channelClass) {
        return channelFactory(new ReflectiveChannelFactory<C>(
                ObjectUtil.checkNotNull(channelClass, "channelClass")
        ));
    }

	public B channelFactory(ChannelFactory<? extends C> channelFactory) {
        ObjectUtil.checkNotNull(channelFactory, "channelFactory");
        if (this.channelFactory != null) {
            throw new IllegalStateException("channelFactory set already");
        }
		// **** 赋值
        this.channelFactory = channelFactory;
        return self();
    }

通过 NioServerSocketChannel 创建 ReflectiveChannelFactory 管道工厂, 这里简单介绍 ReflectiveChannelFactory 实现, 通过 NioServerSocketChannel 根据class类型获取构造器并创建对象.

方法:childHandler(ChannelHandler) 配置管道处理器

自定义实现 ChannelHandler 实现, 这里配置的是 ChannelInitializer 并实现 initChannel 抽象方法. 可通过管道获取 ChannelPipeline 对象获取到上下文实现消息传输
这个暂时不解析, 先按主流程思路走…

方法:bind(端口) 绑定端口

根据端口创建 InetSocketAddress 对象. 其中 doBind(SocketAddress) 方法为核心.
doBind 源码解析:

	private ChannelFuture doBind(final SocketAddress localAddress) {
		// 初始化管道 和 线程池注册管道
        final ChannelFuture regFuture = initAndRegister(); // #see NioEventLoopGroup.register()
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        if (regFuture.isDone()) {   // 如果此任务完成,则返回{@code true}
            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        // EventLoop上的注册失败了,所以当我们试图访问通道的EventLoop时,不能让ChannelPromise直接导致IllegalStateException
                        promise.setFailure(cause);
                    } else {
                        // 注册成功,因此请设置要使用的正确执行程序
                        promise.registered();

                        doBind0(regFuture, channel, localAddress, promise);  // do
                    }
                }
            });
            return promise;
        }
    }

该doBind()方法第一步,是通过 initAndegister() 方法管道初始化和注册管道获取 ChannelFuture 管道响应.
第二步, 通过注册管道得到 ChannelFuture 对象为该注册监听器

初始化管道, 使用管道工厂也就是上面所说的 ReflectiveChannelFactory 对象通过它创建 NioServerSocketChannel 管道。

AbstractBootstrap 中提供了一个抽象方法 init(Channel) 给子类去初始化管道. ServerBootstrap 对象为 NIO 服务端,也就是 AbstractBootstrap 抽象类的实现类.

接下来看服务端如何初始化管道的…

	void init(Channel channel) {
		// 设置管道选项
        setChannelOptions(channel, options0().entrySet().toArray(EMPTY_OPTION_ARRAY), logger);
        // 设置管道的一些属性
        setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));

        ChannelPipeline p = channel.pipeline();     // DefaultChannelPipeline

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions = childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY);

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

服务端在初始化管道先设置了管道选项 setChannelOptions 方法, 设置了管道属性 setAttributes 方法. 在这里二个方法不作深一步解析,有兴趣可以去理解.

channel.pipeline() 方法是获取, 创建的默认的 ChannelPipeline 接口的实现类 DefaultChannelPipeline

ChannelPipeline 理解

ChannelPipeline 类是 ChannelHandler 实例对象的链表,用于处理或截获通道的接收和发送数据。它提供了一种高级的截取过滤模式(类似serverlet中的filter功能),让用户可以在 ChannelPipeline 中完全控制一个事件以及如何处理ChannelHandler与ChannelPipeline的交互。

先跳过 ChannelPipeline 处理 ChannelHandler 逻辑。 我们通过管道获取到 DefaultChannelPipeline 对象. 在这里内部帮我们添加一个 ChannelHandler 管道处理器. ServerBootstrapAcceptor 对象. 并是由单独的线程的运行。

ChannelHanlder 管道处理器, 是由单独的线程来处理的

通过上述理解得知。在 netty 中我们先通过 Channel 获取 管道处理器的管理者。 也是就 ChannelPipeline 对象。通过它添加 ChannelHandlelr 管道处理器. 用它实现我们的消息传输.

看完 ServerBootstrap 重写 init() 方法,咋们回过头再来看 AbstractBootstap 中的 initAndRegister() 方法逻辑. 把管道注册到 NioEventLoopGroup 对象上。下面先看看 NioEventLoopGroup 的初始化流程…

最后看 ChannelPipeline 处理 ChannelHandler 的呢…

NioEventLoopGroup 初始化流程

在看 NioEventLoopGroup 注册管道前, 我们先来看下它的类结构.

一级 NioEventLoopGroup =>
二级 MultithreadEventLoopGroup => 实现 EventLoopGroup 接口
三级 MultithreadEventExecutorGroup =>
四级 AbstractEventExecutorGroup => 实现 EventExecutorGroup 接口

除了 NioEventLoopGroup 其它都是抽象类. 我们来看下 一级 NioEventLoopGroup 的初始化流程吧

	public NioEventLoopGroup() {
        this(0); //默认线程数为0
    }

    public NioEventLoopGroup(int nThreads) {
        this(nThreads, (Executor) null); //默认执行器为null
    }

	public NioEventLoopGroup(int nThreads, Executor executor) {
        this(nThreads, executor, SelectorProvider.provider());//
    }

	public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider) {
        this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);//
    }

	public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
        super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
    }

	// newChild 方法为三级类中的抽象方法
	@Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        EventLoopTaskQueueFactory queueFactory = args.length == 4 (EventLoopTaskQueueFactory) args[3] : null;
        return new NioEventLoop(this, executor, (SelectorProvider) args[0],
            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2], queueFactory);
    }

在一级类构造器中使用到以下三个对象: NioEventLoopGroup 类中的 newChild() 方法中创建 NioEventLoop 时需要
SelectorProvider.provider() :: 选择器提供者
DefaultSelectStrategyFactory.INSTANCE :: 选择器策略模式工厂
RejectedExecutionHandlers.reject() :: 可以理解为异常处理器

二级 MultithreadEventLoopGroup 初始化

	protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }

在二级构造器里面发现如果不设置线程数,就会有个默认的线程数变量 DEFAULT_EVENT_LOOP_THREADS
默认线程数是取的虚拟机可用的处理器数量的二倍 * 2 。 这里可以通过设置 netty 的属性设置 io.netty.eventLoopThreads 线程数。
DEFAULT_EVENT_LOOP_THREADS
三级 MultithreadEventExecutorGroup 初始化

	protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
        this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
    }

	protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }

        if (executor == null) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }

        children = new EventExecutor[nThreads];

        for (int i = 0; i < nThreads; i++) {
            boolean success = false;
            try {
                children[i] = newChild(executor, args); // create
                success = true;
            } catch (Exception e) {
                // TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
                if (!success) {
                    for (int j = 0; j < i; j++) {
                        children[j].shutdownGracefully();
                    }

                    for (int j = 0; j < i; j++) {
                        EventExecutor e = children[j];
                        try {
                            while (!e.isTerminated()) {
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
                            // Let the caller handle the interruption.
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }

        // PowerOfTwoEventExecutorChooser
        chooser = chooserFactory.newChooser(children);

        final FutureListener<Object> terminationListener = new FutureListener<Object>() {
            @Override
            public void operationComplete(Future<Object> future) throws Exception {
                if (terminatedChildren.incrementAndGet() == children.length) {
                    terminationFuture.setSuccess(null);
                }
            }
        };

        for (EventExecutor e : children) {
            e.terminationFuture().addListener(terminationListener);
        }

        Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
        Collections.addAll(childrenSet, children);
        readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }

注意: 三级类中的构造器初始化。其中有个 EventExecutor [] 事件执行器数组, 与 EventExecutorChooserFactory 事件执行器选择器工厂对象
步骤:

  1. 如果 Executor 参数为空则创建 ThreadPerTaskExecutor 对象。(这里executor 默认为空)
  2. 创建长度为 虚拟机可用的处理器数量 * 2 的执行器数组。
  3. 为创建的执行器数组中的每个 EventExecutor 创建赋值, 这里看一级类 NioEventLoopGroup 的 newChild() 重写方法。
  4. 创建 EventExecutorChooserFactory 工厂, 根据执行器数组长度来判断创建对象。这里创建为 PowerOfTwoEventExecutorChooser 该对象主要用来选取数组中的 EventExecutor 。
  5. 创建 FutureListener 监听器, 为每个 EventExecutor 添加这个监听器。
  6. 复制 事件执行器 到新的集合, readonlyChildren 属性为已经读取的事件执行器。
    在这里插入图片描述
    DefaultEventExecutorChooserFactory 工厂 创建 事件执行选择器 逻辑。 如果为长度是为2的n次幂的则创建PowerOfTwoEventExecutorChooser 对象, 否则创建 GenericEventExecutorChooser 对象。
    Power 取 EventExecutor 的逻辑为 下图
	public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }

	private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;
    }

选取 EventExecutor数组中的逻辑…
在这里插入图片描述

NioEventLoopGroup 注册管道流程

AbstractBootstrap 中的 initAndRegister() 方法中通过拿到一级类 NioEventLoopGroup 对象然后把 Channel 注册到当中。
具体注册实现步骤:

  1. 在二级类 MultithreadEventLoopGroupregister() 方法处理逻辑。
    1. 在三级类 MultithreadEventExecutorGroup 通过 EventExecutorChooser 事件执行选择器,获取选择的 EventExecutor (选取规则上图标记部份)
    2. 通过 EventExecutor 的实现类 NioEventLoop 对象注册管道 Channel 。

上述中发现, NioEventLoopGroup 注册管道,交给了 NioEventLoop. 而 NioEventLoopGroup 就是只做了一个 创建 NioEventLoop 和 选择器选取 NioEventLoop 操作。

NioEventLoop 初始化流程

先来看 NioEventLoop 初始化流程. 在创建 NioEventLoop 时有几个重要的参数。我们来回顾一下。

参数一: NioEventLoopGroup 也就是创建的对象, 该包含所有的 EventExecutor
参数二: Executor 执行器 , 在NioEventLoopGroup的三级类 MultithreadEventExecutorGroup 中初始化
默认创建的是, ThreadPerTaskExecutor 对象。
参数三: SelectorProvider 选择器提供者, 这个jdk 用来创建 Selector 的。
参数四: SelectStrategy 选择器策略
参数五: RejectedExecutionHandler 拒绝执行处理器,可以理解为异常处理器

里面几个重要属性:
java.nio.channels.Selector
java.nio.channels.spi.SelectorProvider
io.netty.util.concurrent.EventExecutorGroup
java.util.concurrent.Executor
java.util.Queue

回到 NioEventLoop 注册逻辑上, 下面代码发现.

	// 二级类 SingleThreadEventLoop 中的 register() 方法逻辑
	public ChannelFuture register(Channel channel) {
        return register(new DefaultChannelPromise(channel, this));
    }

	public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        promise.channel().unsafe().register(this, promise);
        return promise;
    }

  1. 创建了 DefaultChannelPromise 对象。
  2. 拿到 Channel 中的 Unsafe 对象. 为二级类 AbstractNioMessageChannel 中的内部类 一级NioMessageUnsafe 对象。
  3. 注册逻辑在内部类 三级类 NioMessageUnsafe 中, 注册管道逻辑看下源码。
    1. 先判断是否注册,如已注册直接返回错误信息
    2. 判断 eventLoop 是否为 NioEventLoop
    3. NioEventLoop 赋值到当前 Channel 上。 也就是说 EventLoop 对应一个 Channel。
    4. isEventLoop() 判断当前线程与 NioEventLoop 中的 thread 线程是否相等. 这里创建 NioEventLoop 中的线程属性是null, 所以不相等。 false
    5. 这里为 EventLoop 创建一个新的线程并执行调用 register0(ChannelPromise) 方法。
  4. 注册 register0(ChannelPromise) 方法逻辑。
    1. 检查通道是否仍然打开,因为当寄存器调用在 eventLoopFuture 之外时,通道可能会关闭,从而无法取消。
    2. doRegister() 逻辑, 在 Channel 的三级类中 AbstractNioChannel 重写,
      1. 拿到 ServerSocketChannel 服务端, 注册 Selector, 和 ops 为 0, 和属性 当前 NioServerSocketChannel 对象。
      2. 返回拿到 SelectionKey 值。
    3. 通过第二步注册之后, 设置属性标识 《已注册》
    4. 通过 DefaultChannelPipeline 调用 invokeHandlerAddedIfNeeded() … 这个处理消息逻辑下面单独分析…
    5. 指定的 DefaultChannelPromise 标记为成功。如果已经完成,那么记录一条消息
    6. 通过 DefaultChannelPipeline 调用 fireChannelRegistered()
    7. 判断 管道是否打开, 以及管道是否 isBound(). 这里是未绑定的. false。 所以先不分析里面的逻辑。
		 AbstractChannel$AbstractUnsafe 内部类的对象中. 注册逻辑 
		public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            ObjectUtil.checkNotNull(eventLoop, "eventLoop");
            if (isRegistered()) {
                promise.setFailure(new IllegalStateException("registered to an event loop already"));
                return;
            }
            if (!isCompatible(eventLoop)) {
                promise.setFailure(new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
                return;
            }

            AbstractChannel.this.eventLoop = eventLoop;

            if (eventLoop.inEventLoop()) {
                register0(promise);
            } else {
                try {
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            register0(promise);
                        }
                    });
                } catch (Throwable t) {
                    logger.warn("Force-closing a channel whose registration task was not accepted by an event loop: {}",
                            AbstractChannel.this, t);
                    closeForcibly();
                    closeFuture.setClosed();
                    safeSetFailure(promise, t);
                }
            }
        }

		private void register0(ChannelPromise promise) {
            try {
                // 请检查通道是否仍然打开,因为当寄存器调用在 eventLoopFuture 之外时,通道可能会关闭,从而无法取消
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = neverRegistered;
                // 设置ServerSocketChannel 注册选择器
                doRegister();   // AbstractNioChannel#doRegister(): 使用ServerSocketChannel 注册到 Selector 得到 SelectionKey
                // 设置标识为已注册
                neverRegistered = false;    // 绝不
                registered = true;

                // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
                // user may already fire events through the pipeline in the ChannelFutureListener.
                pipeline.invokeHandlerAddedIfNeeded();

                safeSetSuccess(promise);
                pipeline.fireChannelRegistered();
                // Only fire a channelActive if the channel has never been registered. This prevents firing
                // multiple channel actives if the channel is deregistered and re-registered.
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {
                        // This channel was registered before and autoRead() is set. This means we need to begin read
                        // again so that we process inbound data.
                        //
                        // See https://github.com/netty/netty/issues/4805
                        beginRead();
                    }
                }
            } catch (Throwable t) {
                // Close the channel directly to avoid FD leak.
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }

	/ AbstractNioChannel 类中方法 doRegister 注册逻辑
	protected void doRegister() throws Exception {
        boolean selected = false;
        for (; ; ) {
            try {
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch (CancelledKeyException e) {
                if (!selected) {
                    // Force the Selector to select now as the "canceled" SelectionKey may still be
                    // cached and not removed because no Select.select(..) operation was called yet.
                    eventLoop().selectNow();
                    selected = true;
                } else {
                    // We forced a select operation on the selector before but the SelectionKey is still cached
                    // for whatever reason. JDK bug ?
                    throw e;
                }
            }
        }
    }

在这里插入图片描述

ChannelPipeline 处理 ChannelHandler

DefaultChannelPipeline 分析

先从这个 invokeHandlerAddedIfNeeded() 方法分析…

	final void invokeHandlerAddedIfNeeded() {
        assert channel.eventLoop().inEventLoop();
        if (firstRegistration) {
            firstRegistration = false;
            // We are now registered to the EventLoop. It's time to call the callbacks for the ChannelHandlers,
            // that were added before the registration was done.
            callHandlerAddedForAllHandlers();
        }
    }

	private void callHandlerAddedForAllHandlers() {
        final PendingHandlerCallback pendingHandlerCallbackHead;
        synchronized (this) {
            assert !registered;
            registered = true;
            pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
            this.pendingHandlerCallbackHead = null;
        }
        PendingHandlerCallback task = pendingHandlerCallbackHead;
        while (task != null) {
            task.execute();
            task = task.next;
        }
    }

DefaultChannelPipeline 中属性分析, 类中含 AbstractChannelHandlerContext 对象 head头部tail尾部

AbstractChannelHandlerContext 双向链表分析:

默认实现为, DefaultChannelHandlerContext
内部类实现, HeadChannelHandlerContext
内部类实现, TailChannelHandlerContext

可以理解为双向链表. AbstractChannelHandlerContext 内部包含自身 next, prev 。 最主要的属性为 EventExecutor 对象, 事件执行器. 也可以说是一个线程。还有一些标记状态.

在这里插入图片描述

实现了 ChannelHandlerContext 接口, 该接口又继承了 ChannelInboundInvokerChannelOutboundInvoker 接口。
接口介绍
在这里插入图片描述
在这里插入图片描述

发现就是通过其ChannelHandlerContext 处理器上下文 处理信息传输。
通过单独的线程处理 传输任务。

分析完结… 后续整理

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值