Netty整体流程分析
接下来就是Netty整体流程的源码讲解了,因为这部分内容十分的长,所以会分开多个小节来讲解。
//eventLoop暂时理解为线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
//ServerBootStrap是启动必备的,启动相关的工作基本都是由它完成的
ServerBootstrap sb = new ServerBootstrap();
sb.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ServerChannelInitializer());
//bind()方法是整个服务启动的一个关键方法,并且同步
ChannelFuture future = sb.bind().sync();
future.channel().closeFuture().sync();
}finally {
group.shutdownGracefully().sync();
}
前面我们也写过一个Demo,基本上就这几行代码,就让我们的Netty跑起来并且实现了通信,那它背后都做了哪些事呢?接下来就以服务端启动为代表讲解下背后的流程:
首先是实例化了EventLoopGroup和ServerBootStrap两个对象,EventLoopGroup前面一个章节已经讲过了,那么接下来重头戏自然就是ServerBootStrap,实例化出ServerBootStrap后就对实例进行各种配置,基本上就是简单地set,比较特别的一个点就是上面的channel(NioServerSocketChannel.class)方法,这里很明显,参数是一个class类型变量,Netty将通过反射产生这个类型的实例对象。
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
} else {
//主要看ReflectiveChannelFactory(channelClass)这个类
return this.channelFactory((io.netty.channel.ChannelFactory)(new ReflectiveChannelFactory(channelClass)));
}
}
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
//这个就是channel()方法参数传进来的class对象,会通过构造函数存进来
private final Class<? extends T> clazz;
public ReflectiveChannelFactory(Class<? extends T> clazz) {
if (clazz == null) {
throw new NullPointerException("clazz");
} else {
//将class对象放入成员变量clazz
this.clazz = clazz;
}
}
//这个类主要看这个方法,看方法名就知道是实例化对象的方法
public T newChannel() {
try {
//这个代码有玩过反射的读者肯定不陌生,就是通过反射实例化对象,然后return出去。
return (Channel)this.clazz.getConstructor().newInstance();
} catch (Throwable var2) {
throw new ChannelException("Unable to create Channel from class " + this.clazz, var2);
}
}
public String toString() {
return StringUtil.simpleClassName(this.clazz) + ".class";
}
}
对ServerBootstrap实例对象进行各种设置之后,Netty又做了什么?接下来就到了最重要的一个方法——bind(),这个方法是整个服务端启动的根源地。
public ChannelFuture bind() {
//先进行一系列校验
this.validate();
SocketAddress localAddress = this.localAddress;
if (localAddress == null) {
throw new IllegalStateException("localAddress not set");
} else {
//最关键的就是doBind()方法
return this.doBind(localAddress);
}
}
private ChannelFuture doBind(final SocketAddress localAddress) {
//这个方法是对Channel的创建new、初始化init和注册Register
final ChannelFuture regFuture = this.initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
} else if (regFuture.isDone()) {
ChannelPromise promise = channel.newPromise();
//接下来看这个doBind0()方法,主要是进行绑定
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
promise.setFailure(cause);
} else {
promise.registered();
AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
doBind方法中,主要是initAndRegister和doBind0两个方法。首先就是initAndRegister这个方法:
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
//这个方法熟悉不?在前面讲解AbstractBootstrap.channel()方法时就讲到了
//newChannel是通过反射的方式创建了一个channel实例,这里是创建一个NioServerSocketChannel
//所以进入到NioServerSocketChannel的构造函数看看
channel = this.channelFactory.newChannel();
//初始化刚生成的NioServerSocketChannel,主要是将参数配置加入到channel,并且加入handler
this.init(channel);
} catch (Throwable var3) {
if (channel != null) {
channel.unsafe().closeForcibly();
return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
}
return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);
}
//这里进行注册register,将channel注册到eventLoop中
ChannelFuture regFuture = this.config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
private static java.nio.channels.ServerSocketChannel newSocket(SelectorProvider provider) {
try {
//生成一个JDK 中的 ServerSocketChannel
return provider.openServerSocketChannel();
} catch (IOException var2) {
throw new ChannelException("Failed to open a server socket.", var2);
}
}
public NioServerSocketChannel() {
//调用上面的newSocket方法,参数就是一个JDK中的ServerSocketChannel
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioServerSocketChannel(SelectorProvider provider) {
this(newSocket(provider));
}
public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
//channel是一个ServerSocketChannel
//可以看到这里传入了一个16表示当前channel将会对accept事件感兴趣
super((Channel)null, channel, 16);
this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this,this.javaChannel().socket());
}
接着往上层父类中看,来到AbstractNioChannel这个类:
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
//ch是ServerSocketChannel
this.ch = ch;
//这个就是16,也就是accept事件
this.readInterestOp = readInterestOp;
try {
//这里将通道设置为非阻塞的
ch.configureBlocking(false);
} catch (IOException var7) {
try {
ch.close();
} catch (IOException var6) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to close a partially initialized socket.", var6);
}
}
throw new ChannelException("Failed to enter non-blocking mode.", var7);
}
}
继续往上层父类构造函数看:
protected AbstractChannel(Channel parent) {
this.parent = parent;
this.id = this.newId();
this.unsafe = this.newUnsafe();
//在这里创建出来了ChannelPipeline,其实是个DefaultChannelPipeline,看下面的方法就知道了
this.pipeline = this.newChannelPipeline();
}
protected DefaultChannelPipeline newChannelPipeline() {
//接下来就继续看看这个构造方法
return new DefaultChannelPipeline(this);
}
protected DefaultChannelPipeline(Channel channel) {
this.channel = (Channel)ObjectUtil.checkNotNull(channel, "channel");
this.succeededFuture = new SucceededChannelFuture(channel, (EventExecutor)null);
this.voidPromise = new VoidChannelPromise(channel, true);
//pipeline默认创建了两个handler,下面四行代码,就是初始化了tail和head,然后将他们形成双向链表
this.tail = new DefaultChannelPipeline.TailContext(this);
this.head = new DefaultChannelPipeline.HeadContext(this);
this.head.next = this.tail;
this.tail.prev = this.head;
}
//从HeadContext的类声明可以看出,HeadContext既是ChannelHandlerContext又是出站和入站Handler
final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {
}
//从TailContext的类声明可以看出,TailContext既是ChannelHandlerContext又是入站Handler
final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
}
在DefaultChannelPipeline中有很多关于ChannelHandlerContext加入到pipeline中的方法,这里找一个addFirst0方法:其它的也是类似的
private void addFirst0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext nextCtx = this.head.next;
newCtx.prev = this.head;
newCtx.next = nextCtx;
this.head.next = newCtx;
nextCtx.prev = newCtx;
}
这些方法结合上面HeadContext和TailContext的声明,可以得出结论我们增加的任何自定义 handler,一定是放在 TailContext 和 HeadContext 之间,HeadContext 一定是入站的第一个 Handler 和出站的最后一个 Handler,TailContext 是入站的最后一个 Handler。到这里,newChannel()执行完成了,一个NioServerSocketChannel 的实例被创建了。
接下来执行 init(channel),init()是一个抽象方法,实际上调用的是ServerBootStrap中的实现:
void init(Channel channel) throws Exception {
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
setChannelOptions(channel, options, logger);
}
//先会设置各种相关参数
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());
}
}
//拿到channel中的pipeline
ChannelPipeline p = channel.pipeline();
//这里是拿到子channel的一些参数
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(0));
}
synchronized (childAttrs) {
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
}
//往主Channel(也就是NIoServerSocketChannel)中的pipeline加入一个ChannelInitializer,这个类继承自ChannelInboundHandlerAdapter
//ChannelInitializer这个类的主要任务在initChannel方法,这个方法惨数是前面newChannel生成的主channel,也就是NIoServerSocketChannel
//将主channel传进去,然后在里面给主channel中的pipeline添加handler
//实际上这个initChannel()方法需要在pipeline.invokeHandlerAddedIfNeeded()被调用时才会执行,前面有提到过,这里不赘述
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
//这个获取的是ServerBootStrap。handler()中加入的handler,而不是childHandler()中的handler
//因为我们代码中没写ServerBootStrap.handler()方法,所以这里为null
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
//这里是比较关键的地方,它调用主channel绑定的EventLoop中的execute方法来执行一个Runnable
//这个Runnable里面的run方法就是加入了一个处理客户端新连接的Handler----ServerBootstrapAcceptor
//所以接下来主要看EventLoop中的execute方法和ServerBootstrapAcceptor这个Handler
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
先看下EventLoop中的execute方法:
public void execute(Runnable task) {
//首先判断Runnable是否为null
if (task == null) {
throw new NullPointerException("task");
}
//这里判断执行execute的线程是否为EventLoop中的线程
boolean inEventLoop = inEventLoop();
//处理task
addTask(task);
//重点在这里,如果上面的判断为false
if (!inEventLoop) {
//这个方法里开启一个线程赋值到当前的EventLoop中
startThread();
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
private void startThread() {
if (state == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
try {
//来到这个方法,开启一个线程
doStartThread();
} catch (Throwable cause) {
STATE_UPDATER.set(this, ST_NOT_STARTED);
PlatformDependent.throwException(cause);
}
}
}
}
private void doStartThread() {
//断言当前EventLoop的线程是null,如果不为空则抛出异常
assert thread == null;
//这里会调用executor.execute()方法,这个executor在前面EventLoop系列源码解析中的MultithreadEventExecutorGroup构造函数中说过
//他是一个ThreadPerTaskExecutor类型,所以进入到ThreadPerTaskExecutor的execute方法看看
executor.execute(new Runnable() {
@Override
public void run() {
//现在处于一个new Runnable中,所以thread.currentThread现在是一个新的线程,然后赋值到EventLoop的thread属性
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
//这个方法应该都很熟悉了,eventLoop.run(),在讲解EventLoop源码系列那一节就说到了这个方法,不记得的可以回去看看
//大致的执行一个循环遍历事件选择器selector的过程,从这个选择器中不断的拿出事件,然后处理的过程,这里就不赘述了。
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
for (;;) {
int oldState = state;
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
if (logger.isErrorEnabled()) {
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
"be called before run() implementation terminates.");
}
}
try {
// Run all remaining tasks and shutdown hooks.
for (;;) {
if (confirmShutdown()) {
break;
}
}
} finally {
try {
cleanup();
} finally {
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
threadLock.release();
if (!taskQueue.isEmpty()) {
if (logger.isWarnEnabled()) {
logger.warn("An event executor terminated with " +
"non-empty task queue (" + taskQueue.size() + ')');
}
}
terminationFuture.setSuccess(null);
}
}
}
}
});
}
public void execute(Runnable command) {
//主要就是新启一个线程,然后传递到Runnable实例中,也就是上面的Thread.currentThread();所获取到的线程就是这里新启的线程
threadFactory.newThread(command).start();
}
接着来看ServerBootstrapAcceptor,这个handler主要处理客户端新连接,
//它是 ServerBootstrap 的内部类,并且处理入站事件,主要重写了 channelRead 方法和 exceptionCaught 方法。
private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//前面笔者在Unsafe系列源码的NioMessageUnsafe.read()方法讲解中,说到了ServerBootstrapAcceptor.channelRead方法()
//这个msg是一个子Channel,具体怎么来的Channel,在前面NioMessageUnsafe.read()方法有详细的讲解,这里不赘述
final Channel child = (Channel) msg;
//拿到了子channel后就对它进行一些属性配置的赋值,例如childHandler(),option()等设置的属性配置
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
//属性值set完后,就需要将子channel注册到EventLoop中,且与Selector挂钩关注某种事件
//具体的注册过程与马上就要讲的主channelregister是一样的,所以这里不赘述
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
}
将这个handler加入到主channel的pipeline后,主channel的pipeline上就有三个handler:HeadContext(入/出) -> ServerBootstrapAcceptor(入) -> TailContext(入)。
至此init()方法执行完成,主channel初始化完成。接下来将主channel与EventLoop关联起来(子Channel也是一样的),config().group().register(channel)方法,这个方法是抽象方法,最终调用会来到MultithreadEventLoopGroup 的 register(Channel channel)方法:
public ChannelFuture register(Channel channel) {
//这个next()方法实际上就是在group中选择一个EventLoop,然后调用其register方法将channel注册进去。
return next().register(channel);
}
public ChannelFuture register(Channel channel) {
//调用下面的register
return register(new DefaultChannelPromise(channel, this));
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
//实际上调用的是AbstractUnsafe的 register 方法,进到这个方法看看,注意参数this是将当前被选中的eventLoop作为参数传入
//AbstractUnsafe的register是前面在Unsafe源码里专门讲过的
promise.channel().unsafe().register(this, promise);
return promise;
}
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
if (eventLoop == null) {
throw new NullPointerException("eventLoop");
} else if (AbstractChannel.this.isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
} else if (!AbstractChannel.this.isCompatible(eventLoop)) {
promise.setFailure(new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
} else {
//前面一堆的逻辑都是在做校验,如果校验通过了就会来到这个代码块
//这里首先将当前的Channel与参数中的EventLoop建立关系
AbstractChannel.this.eventLoop = eventLoop;
//这个首先进行线程的本地性校验,也就是前面说过得,校验现在执行的线程是不是与Channel关联
//的EventLoop中的线程,如果是则直接执行register0方法,如果不是则调用EventLoop.execute来执行
//最终不管走哪里都是执行register0方法,所以接下来进入register0方法
if (eventLoop.inEventLoop()) {
this.register0(promise);
} else {
try {
//eventLoop.execute()方法前面讲解主channel的init()方法时已经详细讲过,就不赘述了
eventLoop.execute(new Runnable() {
public void run() {
AbstractUnsafe.this.register0(promise);
}
});
} catch (Throwable var4) {
AbstractChannel.logger.warn("Force-closing a channel whose registration task was not accepted by an event loop: {}", AbstractChannel.this, var4);
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var4);
}
}
}
}
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
return;
}
boolean firstRegistration = this.neverRegistered;
//调用doRegister方法,这个方法说了很多次了吧,大概就是将Channel注册到EventLoop中的
//Selector选择器中,但是此时还未将关注的事件注册进去。
AbstractChannel.this.doRegister();
this.neverRegistered = false;
AbstractChannel.this.registered = true;
//执行ChannelInitializer.initChannel,以保证handler被添加到pipeline上。
//现在看到这个应该能想起前面的主channel中的pipeline中加入了一个ChannelInitializer并重写了initChannel方法,就是此时被调用的
AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();
this.safeSetSuccess(promise);
//触发了ChannelRegistered事件,跟ChannelActive作用一样都是在某个特定时间点执行
AbstractChannel.this.pipeline.fireChannelRegistered();
if (AbstractChannel.this.isActive()) {
if (firstRegistration) {
//如果Channel处于活动状态且是第一次注册,则触发ChannelActive事件。
//为什么要判断第一次呢?因为可能是之前register然后deregister了,现在有register的
//防止多次触发ChannelActive事件
AbstractChannel.this.pipeline.fireChannelActive();
} else if (AbstractChannel.this.config().isAutoRead()) {
//如果Channel处于活动状态且不是第一次注册,并设置了AutoRead,则调用beginRead
//beginRead最重要的就是doBeginRead方法,这个之前讲过,就是将Channel关注的事件注册到Selector
this.beginRead();
}
}
} catch (Throwable var3) {
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var3);
}
}
到这里,initAndRegister()方法的主要工作就做完了,这只是doBind()的一步,doBind()方法里还有调用了一个很重要的方法doBind0()方法,这个下个小节继续讲解。