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.