今天来看下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这个实现还没来的及看,明天继续看下。