netty源码解析---bind()(3)---register0()

概述

在netty的bind方法里,经过 channel(NioServerSocketChannel) 的实例化后初始化后,开始向pipeline里添加 handler,然后还会调用register向 bossGroup 里面注册 channel(NioServerSocketChannel),但是这里只会先将这个register0 方法作为一个任务放入任务队列中,然后就会开启reactor ,接着这个线程就会开始执行之前的任务队列,就会执行register0

register0()

private void register0(ChannelPromise promise) {
            try {
  
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = neverRegistered;
                doRegister();
                neverRegistered = false;
                registered = true;
                pipeline.invokeHandlerAddedIfNeeded();

                safeSetSuccess(promise);
                //会执行channelRegistered
                pipeline.fireChannelRegistered();
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {

                        beginRead();
                    }
                }
            } catch (Throwable t) {
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }

真正的核心的注册方法是 doRegister();

    @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch (CancelledKeyException e) {
                if (!selected) {
                    eventLoop().selectNow();
                    selected = true;
                } else {
                    throw e;
                }
            }
        }
    }

虽然这个方法是一个for循环,但是只执行一次就会return

看细节

private final SelectableChannel ch;
protected SelectableChannel javaChannel() {
        return ch;
}

这个变量在笔者之前的netty博客中分析过,这个就是原生的 jdk 的ServerSocketChannel (ServerSocketChannelImpl)
仔细看一看,这里是不是和 jdk 原生的 Nio 很像呢?
eventLoop():就是获取 NioEventLoop 对象,然后通过这个对象获取到这个 NioEventLoop 的选择器(Selector),然后将感兴趣的事件注册到选择器上,但是目前这里是传了 0 ,也就是对任何事件都不感兴趣,所以仅仅只是将这个ServerSocketChannel 注册到了Selector上面而已,然后就return了
还有一点需要注意的是这里的register多传入了一个参数,为什么要传入这个参数呢?
因为netty在接收连接的时候最终调用的依然是Nio的 API 而这个传入的对象是 NioServerSocketChannel 类型 这里面有个属性 ch 其保存的就是JDK原生的 ServerSocketChannel(ServerSocketChannelImpl),也就是说,当有客户端连接的时候就会去获取这个对象,操作原生的
ServerSocketChannel

注册完成后来到 pipeline.invokeHandlerAddedIfNeeded()

	final void invokeHandlerAddedIfNeeded() {
        assert channel.eventLoop().inEventLoop();
        if (firstRegistration) {
            firstRegistration = false;
            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;
        }
    }

这里使用 firstRegistration (默认为true)这个变量保证这个方法只会执行一次

然后在callHandlerAddedForAllHandlers 中 会获取一个pendingHandlerCallbackHead的属性,这个属性是什么呢???
这个属性的类型是 PendingHandlerCallback 类型,这里不知道大家是否有印象,在笔者之前的博客中的addLast方法中,将传入的ChannelInitializer封装成PendingHandlerAddedTask ,这里的pendingHandlerCallbackHead 属性就是这个对象

接着来到execute()

	void execute() {
            EventExecutor executor = ctx.executor();
            if (executor.inEventLoop()) {
                callHandlerAdded0(ctx);
            } else {
                try {
                    executor.execute(this);
                } catch (RejectedExecutionException e) {
                    if (logger.isWarnEnabled()) {
                   	 ...
                                executor, ctx.name(), e);
                    }
                    remove0(ctx);
                    ctx.setRemoved();
                }
            }
        }

ctx.executor() 返回的是 NioEventLoop ,然后调用inEventLoop(),执行到这里Reactor线程已经启动了,所以这里一定是为true

追溯callHandlerAdded0(ctx)

	final void callHandlerAdded() throws Exception {
        if (setAddComplete()) {
            handler().handlerAdded(this);
        }
    }

setAddComplete() : 是修改handler的状态变量判断handlerState等于1
handler() : 获取ChannelInitializer 对象

	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        if (ctx.channel().isRegistered()) {     判断这个channel是否已经注册,这里当然是注册过的
            if (initChannel(ctx)) {
                removeState(ctx);
            }
        }
    }

    private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
        if (initMap.add(ctx)) { 
            try {
                initChannel((C) ctx.channel());
            } catch (Throwable cause) {
                exceptionCaught(ctx, cause);
            } finally {
                //删除此节点
                ChannelPipeline pipeline = ctx.pipeline();
                if (pipeline.context(this) != null) {
                    pipeline.remove(this);
                }
            }
            return true;
        }
        return false;
    }

获取到当前对应的handler (ChannelInitializer),这个initChannel()方法调用的就是 ChannelInitializer 的 initChannel
并且当执行完这个handler之后,在finally中还会将这个节点从pipeline 中 删除

回到这个内部的 handler 继续进行分析

 p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                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));
                    }
                });
            }
        });

调用了config.handler() 这个handler返回的是什么呢?这里返回的其实是我们自己添加的handler,也就是通过handler()方法添加的handler,然后又是addLast()方法进行添加,也就是说我们自己写的handler就是在这里进行添加的

在这个方法的最后又向任务队列里面加了一个任务,这个任务又是去pipeline里面添加一个Handler,这个handler就是与客户端连接相关了,会在笔者后续文章介绍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Netty-WebSocket-Spring-Boot-Starter是一个用于将Websocket集成到Spring Boot应用程序中的库。它使用Netty作为底层框架,提供了一种快速和可靠的方式来处理异步通信。 这个库提供了一种简单的方法来创建Websocket端点,只需要使用注释和POJO类即可。在这些端点上可以添加动态的事件处理程序,以处理连接、断开连接和消息事件等。 此外,Netty-WebSocket-Spring-Boot-Starter还包括了一些安全性的特性,如基于令牌的授权和XSS保护,可以帮助您保持您的Websocket应用程序安全。 总的来说,Netty-WebSocket-Spring-Boot-Starter提供了一种快速和易于使用的方式来构建Websocket应用程序,使得它成为应用程序开发人员的有用工具。 ### 回答2: netty-websocket-spring-boot-starter 是一个开的 Java Web 开发工具包,主要基于 Netty 框架实现了 WebSocket 协议的支持,同时集成了 Spring Boot 框架,使得开发者可以更加方便地搭建 WebSocket 服务器。 该工具包提供了 WebSocketServer 配置类,通过在 Spring Boot 的启动配置类中调用 WebSocketServer 配置类,即可启动 WebSocket 服务器。同时,该工具包还提供了多种配置参数,如端口号、URI 路径、SSL 配置、认证配置等等,可以根据业务需求进行自定义配置。 此外,该工具包还提供了一些可扩展的接口和抽象类,如 WebSocketHandler、ChannelHandlerAdapter 等,可以通过继承和实现这些接口和抽象类来实现业务逻辑的处理和拓展。 总的来说,netty-websocket-spring-boot-starter 提供了一个高效、简单、易用的 WebSocket 服务器开发框架,可以减少开发者的开发成本和工作量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值