Netty 源码调试
一、环境搭建
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.68.Final</version>
</dependency>
public class NettyServer {
public static void main(String[] args) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyServerHandler());
}
}); //设置处理器
System.out.println("服务器 is ready。。。。。");
ChannelFuture channelFuture = bootstrap.bind(6668).sync();
//对关闭通道进行监听
channelFuture.channel().closeFuture().sync();
}
}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
//读取客户端对消息
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("server ctx "+ ctx);
ByteBuf buf = (ByteBuf) msg;
System.out.println("客户端发生消息是:"+buf.toString(StandardCharsets.UTF_8));
System.out.println("客户端地址:"+ctx.channel().remoteAddress());
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.channel().eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端..2",StandardCharsets.UTF_8));
}catch (Exception e){
}
}
});
ctx.channel().eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端..3",StandardCharsets.UTF_8));
}catch (Exception e){
}
}
});
Thread.sleep(5000);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端..1",StandardCharsets.UTF_8));
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
}
//发生异常 关闭通道
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.channel().close();
}
}
二、开始调试
1、netty启动入口
首先是这一行代码–>ChannelFuture channelFuture = bootstrap.bind(6668).sync();
点进bind方法之后
public ChannelFuture bind(int inetPort) {
//将port封装成一个对象
return this.bind(new InetSocketAddress(inetPort));
}
继续往下点
public ChannelFuture bind(SocketAddress localAddress) {
//从方法名上剋看出 是先校验 之后再执行doBind方法,有spring方法起名的味道了
this.validate();
return this.doBind((SocketAddress)ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
点进去doBind方法 我们看到一堆代码。。。。
private ChannelFuture doBind(final SocketAddress localAddress) {
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(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;
}
}
但是核心操作只有两步
//第一步 初始化并注册
final ChannelFuture regFuture = this.initAndRegister();
//第二部进行绑定
doBind0(regFuture, channel, localAddress, promise);
接下来 我们就要主要探究这两个步骤!!
2、initAndRegister()
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = this.channelFactory.newChannel();
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);
}
ChannelFuture regFuture = this.config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
我们接着看他的关键步骤:
1、newChannel() ; 创建一个channel
2、this.init(channel); 初始化这个channel
3、this.config().group().register(channel); 注册这个channel
我们再一个一个点方法探究!!!
newChannel()
@Deprecated
public interface ChannelFactory<T extends Channel> {
T newChannel();
}
我们看到这是个接口,我们就要向下找他的实现类 最终我们找到了ReflectiveChannelFactory类
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
private final Constructor<? extends T> constructor;
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException var3) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) + " does not have a public non-arg constructor", var3);
}
}
public T newChannel() {
try {
return (Channel)this.constructor.newInstance();
} catch (Throwable var2) {
throw new ChannelException("Unable to create Channel from class " + this.constructor.getDeclaringClass(), var2);
}
}
public String toString() {
return StringUtil.simpleClassName(ReflectiveChannelFactory.class) + '(' + StringUtil.simpleClassName(this.constructor.getDeclaringClass()) + ".class)";
}
}
我们看看这个类的代码,非常简单,主要就ReflectiveChannelFactory(args)方法 去获得一个constructor
让我们再返回到我们的小dome中**bootstrap.channel(NioServerSocketChannel.class)我们这一步就是通过反射来创建当时我们设置的Channel类型,具体创建是newChannel()**方法
绕了一圈 其实我们 newChannel()方法就是给我们创建一个我们指定的channel
好了 接下来让我们看看我们指定点NioServerSocketChannel到底是个什么东西,这个类真的很重要!
我们先看一下他的构造器
private static java.nio.channels.ServerSocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openServerSocketChannel();
} catch (IOException var2) {
throw new ChannelException("Failed to open a server socket.", var2);
}
}
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioServerSocketChannel(SelectorProvider provider) {
this(newSocket(provider));
}
public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
super((Channel)null, channel, 16);
this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this, this.javaChannel().socket());
}
他的构造器最终都走回了这个方法
public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
//调用上层方法
super((Channel)null, channel, 16);
//创建config
this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this, this.javaChannel().socket());
}
这个config是我们Netty的一个核心我们要记住他是在Channel初始化的时候就创建了
我们的super一直向上点,会点到AbstractNioChannel这个抽象类,注意看注解!
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
//又向上调用父类的构造方法 并且这个parent是之前设置的null
super(parent);
//设置channel
this.ch = ch;
//设置之前传点那个16 其实就是状态设置为SelectionKey.OP_ACCEPT
this.readInterestOp = readInterestOp;
try {
//这里很像我们jdk nio点时候设置成非阻塞模式
ch.configureBlocking(false);
} catch (IOException var7) {
try {
ch.close();
} catch (IOException var6) {
logger.warn("Failed to close a partially initialized socket.", var6);
}
throw new ChannelException("Failed to enter non-blocking mode.", var7);
}
}
最终我们终于点到了AbstractChannel这个抽象类!我宣布Channel直接通关!!
protected AbstractChannel(Channel parent) {
this.parent = parent;
this.id = this.newId();
this.unsafe = this.newUnsafe();
this.pipeline = this.newChannelPipeline();
}
我们看到这里面有四个属性其中parent我们传过来的是null,所以肯定是null
剩下的三个分别是:
id----> 一看就是个channel标示 并且是直接创建的
unsafe ----> 这个unsafe是不是有点眼熟,我们jdk自带的是不是也有个unsafe,但是这两个不一样,想了解自行百度
pipeline ----> 这不就是netty的核心组建之一。在这里我们不过多的探讨,想了解也自行百度
ps: 当我们newChannelPipeline()的时候会传本身的channel作为参数,所以经常说的Pipeline和channel是相互绑定 !
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);
this.tail = new DefaultChannelPipeline.TailContext(this);
this.head = new DefaultChannelPipeline.HeadContext(this);
this.head.next = this.tail;
this.tail.prev = this.head;
}
现在我们Netty的几大基本组件都出来了:
- Channel
- ChannelConfig
- ChannelId
- Unsafe
- Pipeline
这时候会说我们的channelHandle怎么还没出现,那就要看接下来的init方法了!
init(channel)
以ServerBootstrap的init为例:
void init(Channel channel) {
setChannelOptions(channel, this.newOptionsArray(), logger);
setAttributes(channel, this.newAttributesArray());
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = this.childGroup;
final ChannelHandler currentChildHandler = this.childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(this.childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(this.childAttrs);
p.addLast(new ChannelHandler[]{new ChannelInitializer<Channel>() {
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = ServerBootstrap.this.config.handler();
if (handler != null) {
pipeline.addLast(new ChannelHandler[]{handler});
}
ch.eventLoop().execute(new Runnable() {
public void run() {
pipeline.addLast(new ChannelHandler[]{new ServerBootstrap.ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)});
}
});
}
}});
}
我们接着分解一下,归纳一下核心步骤:
1.设置option和attr
setChannelOptions(channel, this.newOptionsArray(), logger);
setAttributes(channel, this.newAttributesArray());
2、设置新接入channel的option和attr
final EventLoopGroup currentChildGroup = this.childGroup;
final ChannelHandler currentChildHandler = this.childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(this.childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(this.childAttrs);
3.加入新连接处理器
p.addLast(new ChannelHandler[]{new ChannelInitializer<Channel>() {
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = ServerBootstrap.this.config.handler();
if (handler != null) {
pipeline.addLast(new ChannelHandler[]{handler});
}
ch.eventLoop().execute(new Runnable() {
public void run() {
pipeline.addLast(new ChannelHandler[]{new ServerBootstrap.ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)});
}
});
}
}});
我们总结一下,我们发现其实init也没有启动服务,只是初始化了一些基本的配置和属性,以及在pipeline上加入了一个接入器,用来专门接受新连接,我们还得继续往下跟。
register(channel)
ChannelFuture regFuture = this.config().group().register(channel);
我们接着点下去发现是EventLoopGroup的一个接口
public interface EventLoopGroup extends EventExecutorGroup {
EventLoop next();
ChannelFuture register(Channel var1);
ChannelFuture register(ChannelPromise var1);
/** @deprecated */
@Deprecated
ChannelFuture register(Channel var1, ChannelPromise var2);
}
这里是new了一个**ChannelPromise ** channel是他的一个参数,简单看这就是将ChannelPromise注册了一下
public ChannelFuture register(Channel channel) {
return this.register((ChannelPromise)(new DefaultChannelPromise(channel, this)));
}
public ChannelFuture register(ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
这里我们看到他用到了我们channel的unsafe方法的register进行注册,接着往下点
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "eventLoop");
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 {
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
this.register0(promise);
} else {
try {
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);
}
}
}
}
这有一大段代码,但是其中的关键就是一个**register0()**方法
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
this.register0(promise);
} else {
eventLoop.execute(new Runnable() {
public void run() {
AbstractUnsafe.this.register0(promise);
}
});
}
这里我们依然只需要focus重点,先将EventLoop事件循环器绑定到该NioServerSocketChannel上,然后调用 **register0()**
注意这里的doRegister() **fireChannelRegistered()**这两个方法。写了注释
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
return;
}
boolean firstRegistration = this.neverRegistered;
//当调试走完这一步时会调用 我们自己写的handler 中我们重写的 handlerAdded 方法
AbstractChannel.this.doRegister();
this.neverRegistered = false;
AbstractChannel.this.registered = true;
AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();
this.safeSetSuccess(promise);
//当调试到这一步的时候 会调用到我们重写的channelRegistered方法
AbstractChannel.this.pipeline.fireChannelRegistered();
if (AbstractChannel.this.isActive()) {
if (firstRegistration) {
AbstractChannel.this.pipeline.fireChannelActive();
} else if (AbstractChannel.this.config().isAutoRead()) {
this.beginRead();
}
}
} catch (Throwable var3) {
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var3);
}
}
这是大家肯定会任务调用了fireChannelActive()方法就会调用我们重写的channelActive方法,但是我们看一下之前的有一个if判断,判断中有个isActive()方法,我们点进去看是个接口,我们看一下NioServerSocketChannel的实现
public boolean isActive() {
return this.isOpen() && this.javaChannel().socket().isBound();
}
接着点我们进了ServerSocket中
private boolean bound = false;
public boolean isBound() {
// Before 1.3 ServerSockets were always bound during creation
return bound || oldImpl;
}
我们发现这个返回值永远为false,所以**isActive()的返回值永远为空!!我们就进不去fireChannelActive()**方法。我们接着慢慢看~
我们可以逆推在channelActive上下断点看看他的调用栈,这时我们找到了**bind()**方法,还是通过异步执行的!
public final void bind(SocketAddress localAddress, ChannelPromise promise) {
this.assertEventLoop();
if (promise.setUncancellable() && this.ensureOpen(promise)) {
if (Boolean.TRUE.equals(AbstractChannel.this.config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress() && !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
AbstractChannel.logger.warn("A non-root user can't receive a broadcast packet if the socket is not bound to a wildcard address; binding to a non-wildcard address (" + localAddress + ") anyway as requested.");
}
boolean wasActive = AbstractChannel.this.isActive();
try {
AbstractChannel.this.doBind(localAddress);
} catch (Throwable var5) {
this.safeSetFailure(promise, var5);
this.closeIfClosed();
return;
}
------------------------------------------------------------------------------
if (!wasActive && AbstractChannel.this.isActive()) {
this.invokeLater(new Runnable() {
public void run() {
AbstractChannel.this.pipeline.fireChannelActive();
}
});
}
-----------------------------------------------------------------------------
this.safeSetSuccess(promise);
}
}
我们要看一下到底是在哪里异步调用了这个代码 在if上下断点,我们又回到了最初的**dobind()方法在他当中有个doBind0()**方法就是这里!
private static void doBind0(final ChannelFuture regFuture, final Channel channel, final SocketAddress localAddress, final ChannelPromise promise) {
channel.eventLoop().execute(new Runnable() {
public void run() {
if (regFuture.isSuccess()) {
-------------------------------------
//这里看方法我们是在这里绑定port 添加监听
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
-----------------------------------------
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
点进去bind方法,这是调用里面 pipeline 然后进行的绑定!
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return this.pipeline.bind(localAddress, promise);
}
再往里走 我们发现里面有个tail,想想 我们在创建channel的时候会创建pipeline ,创建pipeline的时候就会直接创建这个tail,想起来了吧,如果想深入了解 自行百度
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return this.tail.bind(localAddress, promise);
}
3、doBind0()
上面已经介绍了doBind0()的源码,接下来我们接着往里点点。我们点到他的bind()方法 发现也是一个接口,这次我们点AbstractChannelHandlerContext类下的实现
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
ObjectUtil.checkNotNull(localAddress, "localAddress");
if (this.isNotValidPromise(promise, false)) {
return promise;
} else {
final AbstractChannelHandlerContext next = this.findContextOutbound(512);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, (Object)null, false);
}
return promise;
}
}
我们看到这代码中主要就一个**invokeBind()**方法,接着点进去
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
if (this.invokeHandler()) {
try {
((ChannelOutboundHandler)this.handler()).bind(this, localAddress, promise);
} catch (Throwable var4) {
notifyOutboundHandlerException(var4, promise);
}
} else {
this.bind(localAddress, promise);
}
}
里面是向handler bind,在点进去发现又是一个接口,我们点进这个HeadContext类中的bind方法
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
this.unsafe.bind(localAddress, promise);
}java
我们又发现了unsafe这个属性,我们就只觉度这一个bind方法,点进去看看
public final void bind(SocketAddress localAddress, ChannelPromise promise) {
this.assertEventLoop();
if (promise.setUncancellable() && this.ensureOpen(promise)) {
if (Boolean.TRUE.equals(AbstractChannel.this.config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress() && !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
AbstractChannel.logger.warn("A non-root user can't receive a broadcast packet if the socket is not bound to a wildcard address; binding to a non-wildcard address (" + localAddress + ") anyway as requested.");
}
boolean wasActive = AbstractChannel.this.isActive();
try {
AbstractChannel.this.doBind(localAddress);
} catch (Throwable var5) {
this.safeSetFailure(promise, var5);
this.closeIfClosed();
return;
}
if (!wasActive && AbstractChannel.this.isActive()) {
this.invokeLater(new Runnable() {
public void run() {
AbstractChannel.this.pipeline.fireChannelActive();
}
});
}
this.safeSetSuccess(promise);
}
}
是不是很熟悉,是不是和我们在register中的代码神似,之前的那个isActive()方法返回值必为false,但是按照流程,进入doBind()之后,如果channel被激活,就可以调用我们的fireChannelActive()方法,打印我们在handler中重写的**channelActive()**方法。
**doBind()方法里面接着就调用了doBind0()**方法,
private void doBind0(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
SocketUtils.bind(this.javaChannel(), localAddress);
} else {
SocketUtils.bind(this.javaChannel().socket(), localAddress);
}
}
最终调用的就是我们jdk的bind代码。
public static void bind(final SocketChannel socketChannel, final SocketAddress address) throws IOException {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws IOException {
socketChannel.bind(address);
return null;
}
});
} catch (PrivilegedActionException var3) {
throw (IOException)var3.getCause();
}
}
运行完这一行代码,我们才真正进行了端口绑定。。。
4、对比两次 isActive() 方法 为什么执行效果不同
注册的时候仅仅只是add 和register我们的handler
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
return;
}
boolean firstRegistration = this.neverRegistered;
AbstractChannel.this.doRegister();
this.neverRegistered = false;
AbstractChannel.this.registered = true;
AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();
this.safeSetSuccess(promise);
AbstractChannel.this.pipeline.fireChannelRegistered();
if (AbstractChannel.this.isActive()) {
if (firstRegistration) {
AbstractChannel.this.pipeline.fireChannelActive();
} else if (AbstractChannel.this.config().isAutoRead()) {
this.beginRead();
}
}
} catch (Throwable var3) {
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var3);
}
}
而我们bind操作的时候里面会执行dobind方法,将我们的channel设为active状态
public final void bind(SocketAddress localAddress, ChannelPromise promise) {
this.assertEventLoop();
if (promise.setUncancellable() && this.ensureOpen(promise)) {
if (Boolean.TRUE.equals(AbstractChannel.this.config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress() && !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
AbstractChannel.logger.warn("A non-root user can't receive a broadcast packet if the socket is not bound to a wildcard address; binding to a non-wildcard address (" + localAddress + ") anyway as requested.");
}
boolean wasActive = AbstractChannel.this.isActive();
try {
AbstractChannel.this.doBind(localAddress);
} catch (Throwable var5) {
this.safeSetFailure(promise, var5);
this.closeIfClosed();
return;
}
if (!wasActive && AbstractChannel.this.isActive()) {
this.invokeLater(new Runnable() {
public void run() {
AbstractChannel.this.pipeline.fireChannelActive();
}
});
}
this.safeSetSuccess(promise);
}
}
三、各种组件分析
1、ServerBootstrap
Bootstrap sub-class which allows easy bootstrap of ServerChannel
ServerBootstrap是我们的Netty的启动类,采用了链式编程的风格,我们new 的时候只是new了一个对象,让采用链式编程给他赋了各种参数。
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
我们看一下他的继承情况
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel>
我们new的时候,只是new了一个普通的对象
public ServerBootstrap() { }
当我们调用group()方法的时候,赋值parentGroup的时候我们掉用的父类的方法,并且返回的是this
/**
* Set the {@link EventLoopGroup} for the parent (acceptor) and the child (client). These
* {@link EventLoopGroup}'s are used to handle all the events and IO for {@link ServerChannel} and
* {@link Channel}'s.
*/
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;
}
父类的方法长这样子,返回值还是个范型!
/**
* The {@link EventLoopGroup} which is used to handle all the events for the to-be-created
* {@link Channel}
*/
public B group(EventLoopGroup group) {
ObjectUtil.checkNotNull(group, "group");
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return self();
}
private B self() {
return (B) this;
}
我们点一下这个childGroup看看,我们发现加了volatile关键字,应该是防止指令重排序或者可见性
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new ConcurrentHashMap<AttributeKey<?>, Object>();
private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
private volatile EventLoopGroup childGroup;
private volatile ChannelHandler childHandler;
2、EventLoopGroup
EventLoopGroup是我们netty是处理请求的核心类,主要用于各种调度,我们从构造方法开始,分析一下,我们从NioEventLoopGroup()开始点起,其中有一个SelectorProvider.provider()这个就是创建SelectorProvider我们点进去看一下
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
我们看到这里
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
//AccessController.doPrivileged属于特权操作,下面详说
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
//loadProviderFromProperty方法是通过JDK的参数//-Djava.nio.channels.spi.SelectorProvider=class设置的class来反射构造SelectorProvider
if (loadProviderFromProperty())
return provider;
//loadProviderAsService从jar中的目录META-INF/services配置文件中找参数//java.nio.channels.spi.SelectorProvider=class设置的第一个class来反射构造SelectorProvider
if (loadProviderAsService())
return provider;
//最后都没有则调用不同操作系统版本的JDK里自带的sun.nio.ch.DefaultSelectorProvider来创建SelectorProvider
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
总结SelectorProvider的创建分三步进行: (1)由JDK的参数-Djava.nio.channels.spi.SelectorProvider=class设置的class来反射构造SelectorProvider,找不到就跳转到步骤(2) (2)从jar中的目录META-INF/services配置文件中找参数java.nio.channels.spi.SelectorProvider=class设置的第一个class来反射构造SelectorProvider,找不到就跳转到步骤(3) (3)调用不同操作系统版本的JDK里自带的sun.nio.ch.DefaultSelectorProvider来创建SelectorProvider 一般都会走到最后的步骤(3),而这个步骤里创建的SelectorProvider在各个操作系统对应的JDK里各不相同。sun.nio.ch.DefaultSelectorProvider这个类最终编译后放置在JDK的安装根目录下的jre/lib/rt.jar里。
最后落到了MultithreadEventExecutorGroup类的构造方法上。
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
//判断nThreads合法性
checkPositive(nThreads, "nThreads");
//创建线程池
if (executor == null) {
//下面需要的参数,一开始使用无参的构造方法时, 传递进来的 就是null ,执行这一行代码, 创建默认的线程工厂
//ThreadPerTaskExecutor 意味为当前的事件循环组 创建Executor , 用于 针对每一个任务的Executor 线程的执行器
//newDefaultThreadFactory根据它的特性,可以给线程加名字等,
//比传统的好处是 把创建线程和 定义线程需要做的任务分开, 我们只关心任务, 两者解耦
//每次执行任务都会创建一个线程实体
//NioEventLoop 线程命名规则 nioEventLoop-1-XX 1代表是第几个group XX第几个eventLoop
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
// 创建EventLoop
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
//chooser 在这里 初始化了
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
Netty的executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
默认的线程工厂,创建出的Thread,并不是JDK原生的Thread,而是Netty自己封装的
protected ThreadFactory newDefaultThreadFactory() {
return new DefaultThreadFactory(getClass());
}
点到最后DefaultThreadFactory其实就是去搞各种的参数 但是threadGroup还是为null
public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
ObjectUtil.checkNotNull(poolName, "poolName");
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
throw new IllegalArgumentException(
"priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
}
prefix = poolName + '-' + poolId.incrementAndGet() + '-';
this.daemon = daemon;
this.priority = priority;
this.threadGroup = threadGroup;
}
再看看ThreadPerTaskExecutor,这里实际上使用了设计模式
1、command是用户定义的任务, 命令模式; 直观的 我定义一种任务, 程序不需要知道我执行的命令是什么,但是当我把任务扔给你, 你帮我执行就好了。
2、代理设计模型, 代理了ThreadFactory , 把本来给ThreadPerTaskExecutor执行的任务给了ThreadFactory
public final class ThreadPerTaskExecutor implements Executor {
private final ThreadFactory threadFactory;
public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
this.threadFactory = ObjectUtil.checkNotNull(threadFactory, "threadFactory");
}
//必须实现 Executor 里面唯一的抽象方法, execute , 执行性 任务
@Override
public void execute(Runnable command) {
threadFactory.newThread(command).start();
}
}
其次,上面的newChild(executor, args);方法其实是抽象方法,真正运行时会执行子类NioEventLoopGroup的实现, 如下:
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
SelectorProvider selectorProvider = (SelectorProvider) args[0];
SelectStrategyFactory selectStrategyFactory = (SelectStrategyFactory) args[1];
RejectedExecutionHandler rejectedExecutionHandler = (RejectedExecutionHandler) args[2];
EventLoopTaskQueueFactory taskQueueFactory = null;
EventLoopTaskQueueFactory tailTaskQueueFactory = null;
int argsLength = args.length;
if (argsLength > 3) {
taskQueueFactory = (EventLoopTaskQueueFactory) args[3];
}
if (argsLength > 4) {
tailTaskQueueFactory = (EventLoopTaskQueueFactory) args[4];
}
//这里才是真正的创建事件循环组
return new NioEventLoop(this, executor, selectorProvider,
selectStrategyFactory.newSelectStrategy(),
rejectedExecutionHandler, taskQueueFactory, tailTaskQueueFactory);
}
看一下NioEventLoop的构造方法
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
EventLoopTaskQueueFactory taskQueueFactory, EventLoopTaskQueueFactory tailTaskQueueFactory) {
//进入到父类, 着重看他是如何创建出 TaskQueue的
super(parent, executor, false, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory),
rejectedExecutionHandler);
this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");
this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");
//获取Selector选择器
final SelectorTuple selectorTuple = openSelector();
//SelectorTuple是netty维护 jdk 原生的Selector的包装类, 下面看,他有两个Selector, 一个是经过包装的,一个是未经过包装的
this.selector = selectorTuple.selector;
this.unwrappedSelector = selectorTuple.unwrappedSelector;
}
点进super父类的构造方法点点点SingleThreadEventExecutor
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
boolean addTaskWakesUp, Queue<Runnable> taskQueue,
RejectedExecutionHandler rejectedHandler) {
//调用父类的构造方法,设置自己的父Group
super(parent);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS;
//保存线程执行器
this.executor = ThreadExecutorMap.apply(executor, this);
//保存taskQueue
this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue");
this.rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
在这个类中进行了如下的工作:
调用父类的构造方法,设置自己的父Group
初始化自己的线程执行器
赋值任务队列
队列有啥用?
我们知道,Netty中的线程可不止一个, 多个EventLoop意味着多个线程, 任务队列的作用就是当其他线程拿到CPU的执行权时,却得到了其他线程的IO请求,这时当前线程就把这个请求以任务的方式提交到对应线程的任务队列里面
创建的什么任务队列?
有个误区, 当我跟进 newTaskQueue(this.maxPendingTasks);方法时, 进入的方法创建了一个LinkedBlockingQueue队列, 实际上创建的确是MpscQueue , 这并不奇怪,是因为NioEventLoop把这个方法重写了, 源码如下:
private static Queue<Runnable> newTaskQueue(
EventLoopTaskQueueFactory queueFactory) {
if (queueFactory == null) {
return newTaskQueue0(DEFAULT_MAX_PENDING_TASKS);
}
return queueFactory.newTaskQueue(DEFAULT_MAX_PENDING_TASKS);
}
private static Queue<Runnable> newTaskQueue0(int maxPendingTasks) {
// This event loop never calls takeTask()
return maxPendingTasks == Integer.MAX_VALUE ? PlatformDependent.<Runnable>newMpscQueue()
: PlatformDependent.<Runnable>newMpscQueue(maxPendingTasks);
}
这个任务队列的特性是 非阻塞的,多生产者单消费者, 正好和Netty的线程模型对应
此外,这个SingleThreadEventExecutor还有很多重要的方法
excute执行任务
尝试开启线程(初始化EventLoop的线程)
开启线程
执行所有任务
聚合定时任务
把任务丢进队列
把任务从队列中取出
NioEventLoop打开自己的队列时,做了哪些优化?
通过反射,借助Java.Security.AccessController提供的线程安全的策略执行机制把原生JDK的selector的SelectedKeys这个HashSet替换成了数组,使得他的事件复杂度在任何时刻都是O1
//这里进行了优化,netty把hashSet转换成了数组, 因为在JDK的NIO模型中,获取Selector时, Selector里面内置的存放SelectionKey的容器是Set集合
//而netty把它替换成了自己的数据结构, 数组, 从而使在任何情况下, 它的时间复杂度都是 O1
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
try {
//使用jdk 的api创建新的 selector
unwrappedSelector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
if (DISABLE_KEY_SET_OPTIMIZATION) {
//如果不需要优化,就返回原生的selector , 默认为false 即 使用优化
return new SelectorTuple(unwrappedSelector);
}
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
//通过反射 sun.nio.ch.SelectorImpl 或者这个类
return Class.forName(
"sun.nio.ch.SelectorImpl",
false,
PlatformDependent.getSystemClassLoader());
} catch (Throwable cause) {
return cause;
}
}
});
//判断是否获取到了这个类
if (!(maybeSelectorImplClass instanceof Class) ||
// ensure the current selector implementation is what we can instrument.
!((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) {
if (maybeSelectorImplClass instanceof Throwable) {
Throwable t = (Throwable) maybeSelectorImplClass;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);
}
return new SelectorTuple(unwrappedSelector);
}
//确定是Selector的实现类 换了个名字
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
//接下来 netty会用下面这个SelectedSelectionKeySet数据结构 替换原来的 keySet , 进入查看
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
/**
* 类java.security.AccessController提供了一个默认的安全策略执行机制,它使用栈检查来决定潜在不安全的操作是否被允许。
* 这个访问控制器不能被实例化,它不是一个对象,而是集合在单个类中的多个静态方法。
*/
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
//通过反射, 获取到 selectorImplClass的两个字段 selectedKeys publicSelectedKeys
//selectedKeys publicSelectedKeys底层都是 hashSet() 实现的, 现在获取出来了, 放入上面的数组数据结构中
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
//对jdk1.9的优化
if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
// Let us try to use sun.misc.Unsafe to replace the SelectionKeySet.
// This allows us to also do this in Java9+ without any extra flags.
long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);
long publicSelectedKeysFieldOffset =
PlatformDependent.objectFieldOffset(publicSelectedKeysField);
if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {
PlatformDependent.putObject(
unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);
PlatformDependent.putObject(
unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);
return null;
}
// We could not retrieve the offset, lets try reflection as last-resort.
}
//trySetAccessible 可以强制访问私有的对象
Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true);
if (cause != null) {
return cause;
}
//trySetAccessible 可以强制访问私有的对象
cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true);
if (cause != null) {
return cause;
}
//真正的把通过反射得到的 那两个字段放入我们自己的数据结构中
//下面是把我们的NioEventLoop中的 unwrappedSelector 的 selectedKeysField的属性 直接设置成 优化后的selectedKeySet
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
return null;
} catch (NoSuchFieldException e) {
return e;
} catch (IllegalAccessException e) {
return e;
}
}
});
if (maybeException instanceof Exception) {
selectedKeys = null;
Exception e = (Exception) maybeException;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);
return new SelectorTuple(unwrappedSelector);
}
//初始化自己维护被选中的key的集合 --> 数组类型的
selectedKeys = selectedKeySet;
logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);
return new SelectorTuple(unwrappedSelector,
new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
到现在为止, NioEventLoopGroup和NioEventLoop就都初始化完成了,当然这是初始化,程序运行到现在,依然只有一条主线程, EventLoop的Thread还没start()干活,但是起码已经有能力准备启动了
总结一下:
就像下面的体系一样, 五脏俱全
NioEventLoopGroup
NIoEventLoop
excutor(线程执行器) , 执行IO任务/非IO任务
selector 选择器
Chooser
NioEventLoopGroup 是运行Nio通讯处理网络消息的运行环境维护的是Reactor线程的调用(类似于spring容器维护的是bean的生命周期)
3、Channel
直接上channel的代码,里面还有个unsafe接口,之前的调试中都分析过了。我们这里就简过一下
public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparable<Channel> {
/**
* Returns the globally unique identifier of this {@link Channel}.
*/
ChannelId id();
/**
* Return the {@link EventLoop} this {@link Channel} was registered to.
*/
EventLoop eventLoop();
/**
* Returns the parent of this channel.
*
* @return the parent channel.
* {@code null} if this channel does not have a parent channel.
*/
Channel parent();
/**
* Returns the configuration of this channel.
*/
ChannelConfig config();
/**
* Returns {@code true} if the {@link Channel} is open and may get active later
*/
boolean isOpen();
/**
* Returns {@code true} if the {@link Channel} is registered with an {@link EventLoop}.
*/
boolean isRegistered();
/**
* Return {@code true} if the {@link Channel} is active and so connected.
*/
boolean isActive();
/**
* Return the {@link ChannelMetadata} of the {@link Channel} which describe the nature of the {@link Channel}.
*/
ChannelMetadata metadata();
/**
* Returns the local address where this channel is bound to. The returned
* {@link SocketAddress} is supposed to be down-cast into more concrete
* type such as {@link InetSocketAddress} to retrieve the detailed
* information.
*
* @return the local address of this channel.
* {@code null} if this channel is not bound.
*/
SocketAddress localAddress();
/**
* Returns the remote address where this channel is connected to. The
* returned {@link SocketAddress} is supposed to be down-cast into more
* concrete type such as {@link InetSocketAddress} to retrieve the detailed
* information.
*
* @return the remote address of this channel.
* {@code null} if this channel is not connected.
* If this channel is not connected but it can receive messages
* from arbitrary remote addresses (e.g. {@link DatagramChannel},
* use {@link DatagramPacket#recipient()} to determine
* the origination of the received message as this method will
* return {@code null}.
*/
SocketAddress remoteAddress();
/**
* Returns the {@link ChannelFuture} which will be notified when this
* channel is closed. This method always returns the same future instance.
*/
ChannelFuture closeFuture();
/**
* Returns {@code true} if and only if the I/O thread will perform the
* requested write operation immediately. Any write requests made when
* this method returns {@code false} are queued until the I/O thread is
* ready to process the queued write requests.
*/
boolean isWritable();
/**
* Get how many bytes can be written until {@link #isWritable()} returns {@code false}.
* This quantity will always be non-negative. If {@link #isWritable()} is {@code false} then 0.
*/
long bytesBeforeUnwritable();
/**
* Get how many bytes must be drained from underlying buffers until {@link #isWritable()} returns {@code true}.
* This quantity will always be non-negative. If {@link #isWritable()} is {@code true} then 0.
*/
long bytesBeforeWritable();
/**
* Returns an <em>internal-use-only</em> object that provides unsafe operations.
*/
Unsafe unsafe();
/**
* Return the assigned {@link ChannelPipeline}.
*/
ChannelPipeline pipeline();
/**
* Return the assigned {@link ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
*/
ByteBufAllocator alloc();
@Override
Channel read();
@Override
Channel flush();
/**
* <em>Unsafe</em> operations that should <em>never</em> be called from user-code. These methods
* are only provided to implement the actual transport, and must be invoked from an I/O thread except for the
* following methods:
* <ul>
* <li>{@link #localAddress()}</li>
* <li>{@link #remoteAddress()}</li>
* <li>{@link #closeForcibly()}</li>
* <li>{@link #register(EventLoop, ChannelPromise)}</li>
* <li>{@link #deregister(ChannelPromise)}</li>
* <li>{@link #voidPromise()}</li>
* </ul>
*/
interface Unsafe {
/**
* Return the assigned {@link RecvByteBufAllocator.Handle} which will be used to allocate {@link ByteBuf}'s when
* receiving data.
*/
RecvByteBufAllocator.Handle recvBufAllocHandle();
/**
* Return the {@link SocketAddress} to which is bound local or
* {@code null} if none.
*/
SocketAddress localAddress();
/**
* Return the {@link SocketAddress} to which is bound remote or
* {@code null} if none is bound yet.
*/
SocketAddress remoteAddress();
/**
* Register the {@link Channel} of the {@link ChannelPromise} and notify
* the {@link ChannelFuture} once the registration was complete.
*/
void register(EventLoop eventLoop, ChannelPromise promise);
/**
* Bind the {@link SocketAddress} to the {@link Channel} of the {@link ChannelPromise} and notify
* it once its done.
*/
void bind(SocketAddress localAddress, ChannelPromise promise);
/**
* Connect the {@link Channel} of the given {@link ChannelFuture} with the given remote {@link SocketAddress}.
* If a specific local {@link SocketAddress} should be used it need to be given as argument. Otherwise just
* pass {@code null} to it.
*
* The {@link ChannelPromise} will get notified once the connect operation was complete.
*/
void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
/**
* Disconnect the {@link Channel} of the {@link ChannelFuture} and notify the {@link ChannelPromise} once the
* operation was complete.
*/
void disconnect(ChannelPromise promise);
/**
* Close the {@link Channel} of the {@link ChannelPromise} and notify the {@link ChannelPromise} once the
* operation was complete.
*/
void close(ChannelPromise promise);
/**
* Closes the {@link Channel} immediately without firing any events. Probably only useful
* when registration attempt failed.
*/
void closeForcibly();
/**
* Deregister the {@link Channel} of the {@link ChannelPromise} from {@link EventLoop} and notify the
* {@link ChannelPromise} once the operation was complete.
*/
void deregister(ChannelPromise promise);
/**
* Schedules a read operation that fills the inbound buffer of the first {@link ChannelInboundHandler} in the
* {@link ChannelPipeline}. If there's already a pending read operation, this method does nothing.
*/
void beginRead();
/**
* Schedules a write operation.
*/
void write(Object msg, ChannelPromise promise);
/**
* Flush out all write operations scheduled via {@link #write(Object, ChannelPromise)}.
*/
void flush();
/**
* Return a special ChannelPromise which can be reused and passed to the operations in {@link Unsafe}.
* It will never be notified of a success or error and so is only a placeholder for operations
* that take a {@link ChannelPromise} as argument but for which you not want to get notified.
*/
ChannelPromise voidPromise();
/**
* Returns the {@link ChannelOutboundBuffer} of the {@link Channel} where the pending write requests are stored.
*/
ChannelOutboundBuffer outboundBuffer();
}
}
我们进入ServerChannel这个接口看看
/**
* A {@link Channel} that accepts an incoming connection attempt and creates
* its child {@link Channel}s by accepting them. {@link ServerSocketChannel} is
* a good example.
*/
public interface ServerChannel extends Channel {
// This is a tag interface.
//这仅仅是个tag
}
根据注解,我们知道这个接口仅仅是一个tag接口,说明实现了这个接口的类,也都具有这个接口约定的特性。我们点进我们最长用的ServerSocketChannel看一下
/**
* A TCP/IP {@link ServerChannel} which accepts incoming TCP/IP connections.
*/
public interface ServerSocketChannel extends ServerChannel {
@Override
ServerSocketChannelConfig config();
@Override
InetSocketAddress localAddress();
@Override
InetSocketAddress remoteAddress();
}
4、ChannelPipeLine
ChannelHandler 列表处理和拦截 Channel 的传入事件和传出操作。ChannelPipeline 是 Intercepting Filter 模式的扩展,用户可以完全控制事件的处理方式和管道中 ChannelHandlers 如何交互。
public class DefaultChannelPipeline implements ChannelPipeline {
// head和tail是handler的处理链/上下文
final AbstractChannelHandlerContext head;
final AbstractChannelHandlerContext tail;
private final Channel channel;
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
}
TailContext实现了ChannelOutboundHandler接口,HeadContext实现了ChannelInboundHandler和ChannelOutboundHandler接口,head和tail构成了一个链表。
- InBound:channelRegistered、channelActive、channelRead、channelReadComplete;
- OutBound:bind、connect、close、flush等。