netty源码阅读之服务器启动之服务端channel的初始化

服务端channel的初始化大致分为以下几个步骤:

1、设置channelOptions,channelAttrs

2、设置childOptions,childAttrs

3、配置服务端pipeline:config handler

4、添加连接器,add serverBootstrapAcceptor,以后新的请求的都通过这个连接器处理,给新的连接分配一个nio线程。

 

 初始化用一句话来解释,就是保存用户设置的属性,比较简单。

 

首先,我们在上一篇文章的AbstractBootstrap的initAndRegister方法里面找到init(channel)这个函数,从这里开始,

现在分析的是服务端的,所以实现是ServerBootstrap的实现:

    @Override
    void init(Channel channel) throws Exception {
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            channel.config().setOptions(options);
        }

        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());
            }
        }

        ChannelPipeline p = channel.pipeline();

        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(childOptions.size()));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
        }

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

                // We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler.
                // In this case the initChannel(...) method will only be called after this method returns. Because
                // of this we need to ensure we add our handler in a delayed fashion so all the users handler are
                // placed in front of the ServerBootstrapAcceptor.
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

 

设置channelOptions,channelAttrs

这里的实现很简单,就是把传进来的数据options 和attrs放到map里面:

final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
    channel.config().setOptions(options);
}

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());
    }
}

这这里需要说明的是,我们的用户代码没有设置options。

 

设置childOptions,childAttrs

childOptions和childAttrs是新的链接进来之后,我们需要给她设置的属性,而上面一个设置是服务端自己的属性。

用户的代码在这里设置:

           .childOption(ChannelOption.TCP_NODELAY, true)
           .childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")

点进去看其中一个的实现:

    public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {
        if (childKey == null) {
            throw new NullPointerException("childKey");
        }
        if (value == null) {
            childAttrs.remove(childKey);
        } else {
            childAttrs.put(childKey, value);
        }
        return this;
    }

而这个childAttrs又是一个hashMap:

    private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();

在ServerBootstrap里面,我们这一步也是简单的复制了一下这两个hashMap:

        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
        }

简单。

 

配置服务端pipeline:config handler

上一篇文章我们知道pipeline是在创建服务端channel的时候创建的。

后面有一段代码:

ChannelHandler handler = config.handler();

把用户自定义的handler添加到pipeline里面。

 

添加连接器,add ServerBootstrapAcceptor

无论用户添加过多少的服务端handler,在netty里面都会默认添加这一个处理器

这一步是最重要的,以后我们新的请求都会经过它来初始化,就是这一句:

 pipeline.addLast(new ServerBootstrapAcceptor(
                                currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));

我们一个个分析参数:

 

currentChildGroup:

这是从childGroup来的,然后我们用户端代码有一段:b.group(bossGroup, workerGroup),点进去看,这个workerGroup就是我们ServerBootstrap的childGroup:

    public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (childGroup == null) {
            throw new NullPointerException("childGroup");
        }
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = childGroup;
        return this;
    }

 

currentChildHandler:

这个其实也是从下面的用户代码进来的:

.childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new AuthHandler());
                            //..

                        }
                    });

 

currentChildOptions, currentChildAttrs:

这个就是我们上面第二步添加的childOptions和childAttrs

 

初始化比较简单,重点在最后一步添加连接器ServerBootstrapAcceptor。

后面还会详细分析。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值