Netty源码阅读系列(一)

今天来看下Netty的源码。

下载源码

首先从github下载Netty的源码,推荐下载4.1版本,传送门:https://github.com/netty/netty.git,如果下载的慢可以试下我以前说的国内镜像,下载下来之后用maven安装下依赖。

开始阅读

首先我们看下整个项目结构如下:

东西很多是不是,完全不知道从哪里开始看。

我说下我的思路,你们看看是否有帮助,如果你对netty没用过,推荐先看看example包看下实例;如果你对Netty有一定了解,想要加深,可以找平时Netty比较常用的几个类Bootstrap,ServerBootstrap,ChinnelHandler,ChinnelPipeline这些,看看它们在哪个包,然后先看那个包的内容。

出乎意料的,这几个类都在一个包下,它应该就是Netty里面比较核心的包了。结构如下:

在这里插入图片描述

可以看到bootstrap包的结构比较清晰,里面都是Bootstrap相关的实现类,超类是AbstractBootstrap和AbstractBootStrapConfig。BootStrap和ServerBootStrap都是它的实现类。这个包里面还有一个FailedChannel,和里面其他类画风有点不一样,先暂时不管。

AbstractBootstrapConfig

首先看下AbstractBootstrapConfig类,它的实现就很简单,而且和一般的Config类不一样,它不是用来"配置"Bootstrap类的,它里面有一个Bootstrap的成员变量,然后方法全是返回的bootStrap的字段值,这个怎么看都像是一个存储容器,专门返回各种配置的。这个和我们平时看到的xxxConfig完全是两个东西,别弄混了。

在这里插入图片描述

AbstractBootstrap

AbstractBootstrap是一个帮助类启动Channel,Channel在Netty里面是一种连接的抽象,你可以把一个Channel想象成一个连接。

首先看下它的构造函数:

    AbstractBootstrap(AbstractBootstrap<B, C> bootstrap) {
        group = bootstrap.group;
        channelFactory = bootstrap.channelFactory;
        handler = bootstrap.handler;
        localAddress = bootstrap.localAddress;
        synchronized (bootstrap.options) {
            options.putAll(bootstrap.options);
        }
        attrs.putAll(bootstrap.attrs);
    }

在创建的时候初始化了很多东西,比如group,channelFactory,handler,localAddress,options,attrs。但是这个我们基本用不到,实际中我们都是单个设置的。

里面有两个方法需要注意下,就是ChannelOption和attr设置的时候如果值为Null会删除原来那个key对应的值,如下:

/**
 * Allow to specify a {@link ChannelOption} which is used for the {@link Channel} instances once they got
 * created. Use a value of {@code null} to remove a previous set {@link ChannelOption}.
 */
public <T> B option(ChannelOption<T> option, T value) {
    ObjectUtil.checkNotNull(option, "option");
    synchronized (options) {
        if (value == null) {
            options.remove(option);
        } else {
            options.put(option, value);
        }
    }
    return self();
}

/**
 * Allow to specify an initial attribute of the newly created {@link Channel}.  If the {@code value} is
 * {@code null}, the attribute of the specified {@code key} is removed.
 */
public <T> B attr(AttributeKey<T> key, T value) {
    ObjectUtil.checkNotNull(key, "key");
    if (value == null) {
        attrs.remove(key);
    } else {
        attrs.put(key, value);
    }
    return self();
}
ServerBootstrap

我们看下ServerBootstrap这个常用的服务端引导类。

我们想下,一个常见的ServerBootstrap是怎么用的?大概下面这样:

ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .option(ChannelOption.SO_BACKLOG, 100)
 .handler(new LoggingHandler(LogLevel.INFO))
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
         ChannelPipeline p = ch.pipeline();
         if (sslCtx != null) {
             p.addLast(sslCtx.newHandler(ch.alloc()));
         }
         //p.addLast(new LoggingHandler(LogLevel.INFO));
         p.addLast(serverHandler);
     }
 });

我们在源码里看看做了什么呢?首先new了一个空的构造函数,源码如下,其实里面什么逻辑都没有,就是分配了下内存初始化了实例。

public ServerBootstrap() { }

然后group(boosGroup,workerGroup)做啥了呢?就是给childGroup和group进行了赋值而已。

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

channel(NioServerSocketChannel.class)就是创建了一个channelFactory的实例,里面有一个NioServerSocketChannel。

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

option(ChannelOption.SO_BACKLOG, 100)这个就是上面说的那个需要注意的key那段的方法,主要是给channel设置属性的。

handler(new LoggingHandler(LogLevel.INFO))就是设置了一个handler。

public B handler(ChannelHandler handler) {
    this.handler = ObjectUtil.checkNotNull(handler, "handler");
    return self();
}

childHandler(new ChannelInitializer() {)里面会要求传一个channelHandler,但是这个需要是一个初始化器。

public ServerBootstrap childHandler(ChannelHandler childHandler) {
    this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
    return this;
}

为什么childHandler需要初始化器而handler方法不需要呢?是因为handler的初始化是在代码里面帮忙做好了的,具体执行时在ServerBootstrap执行bind(port)方法时执行的,会调用里面的init方法:

@Override
void init(Channel channel) {
    setChannelOptions(channel, newOptionsArray(), logger);
    setAttributes(channel, newAttributesArray());

    ChannelPipeline p = channel.pipeline();

    final EventLoopGroup currentChildGroup = childGroup;
    final ChannelHandler currentChildHandler = childHandler;
    final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
    final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);

    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));
                }
            });
        }
    });
}
总结

今天大概看了下ServerBootstrap的实现,Bootstrap这个实现还没来的及看,明天继续看下。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值