Netty源码分析---NioServerSocketChannel-Unsafe初始化详解

相关文章链接

位运算详解

waken方法详解

ThreadPerTaskExecutor与线程创建详解

processSelectedKeys() vs runAllTasks()

NioServerSocketChannel-Unsafe初始化详解

NioEventLoop的run方法详解

NioEventLoopGroup深度解析

inEventLoop方法详解

executionMask详解

Netty源码分析–认真系列(一)

Netty源码分析–认真系列(二)

NioServerSocketChannel Unsafe 初始化详解

问题

在 Netty 服务端启动过程中,NioServerSocketChannelunsafe 字段到底是什么类型?为什么是这个类型?

答案

NioServerSocketChannelunsafe 字段是 NioMessageUnsafe 类型的实例。

本文档将从构造函数开始,逐步追踪代码,解释这个结论是如何得出的。


前置知识:类继承关系

在开始追踪代码之前,先了解 NioServerSocketChannel 的继承关系:

AbstractChannel (最顶层父类)
    ↑ 继承
AbstractNioChannel
    ↑ 继承
AbstractNioMessageChannel (实现了 newUnsafe() 方法)
    ↑ 继承
NioServerSocketChannel (我们创建的类)

关键点

  • AbstractChannel 定义了 unsafe 字段
  • AbstractChannel 定义了抽象方法 newUnsafe()
  • AbstractNioMessageChannel 实现了 newUnsafe() 方法

代码追踪:从构造函数到 unsafe 初始化

步骤 1:创建 NioServerSocketChannel 对象

// ServerBootstrap 启动时
Channel channel = new NioServerSocketChannel();

这行代码会触发 NioServerSocketChannel 的构造方法。


步骤 2:NioServerSocketChannel 无参构造方法

位置io.netty.channel.socket.nio.NioServerSocketChannel

public class NioServerSocketChannel extends AbstractNioMessageChannel 
                                    implements ServerSocketChannel {
    
    private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = 
        SelectorProvider.provider();
    
    // 【入口】无参构造方法
    public NioServerSocketChannel() {
        // 调用本类的另一个构造方法
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }
    
    // 创建 Java NIO 的 ServerSocketChannel
    private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException("Failed to open a server socket.", e);
        }
    }
}

说明

  • 调用 newSocket() 创建 Java NIO 的 ServerSocketChannel
  • 然后调用本类的重载构造方法

步骤 3:NioServerSocketChannel 有参构造方法

位置io.netty.channel.socket.nio.NioServerSocketChannel

public NioServerSocketChannel(ServerSocketChannel channel) {
    // 调用父类 AbstractNioMessageChannel 的构造方法
    // 参数:parent=null, channel=ServerSocketChannel, readInterestOp=OP_ACCEPT
    super(null, channel, SelectionKey.OP_ACCEPT);
    
    // 创建配置对象(与 unsafe 无关,略过)
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

说明

  • 调用父类 AbstractNioMessageChannel 的构造方法
  • 传入 OP_ACCEPT 表示关注接受连接事件

步骤 4:AbstractNioMessageChannel 构造方法

位置io.netty.channel.nio.AbstractNioMessageChannel

public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
    
    protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        // 继续调用父类 AbstractNioChannel 的构造方法
        super(parent, ch, readInterestOp);
    }
}

说明

  • 这个类没有做额外处理,直接调用父类构造方法
  • 注意:这个类后面会实现 newUnsafe() 方法(见步骤 7)

步骤 5:AbstractNioChannel 构造方法

位置io.netty.channel.nio.AbstractNioChannel

public abstract class AbstractNioChannel extends AbstractChannel {
    
    private final SelectableChannel ch;
    protected final int readInterestOp;
    
    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        // 继续调用父类 AbstractChannel 的构造方法
        super(parent);
        
        // 保存 Java NIO 的 Channel
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        
        try {
            // 设置为非阻塞模式
            ch.configureBlocking(false);
        } catch (IOException e) {
            // ... 异常处理
        }
    }
}

说明

  • 保存 Java NIO 的 SelectableChannel
  • 设置为非阻塞模式
  • 继续调用父类 AbstractChannel 的构造方法

步骤 6:AbstractChannel 构造方法(核心!)

位置io.netty.channel.AbstractChannel

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    
    private final Channel parent;
    private final ChannelId id;
    private final Unsafe unsafe;  // unsafe 字段在这里定义
    private final DefaultChannelPipeline pipeline;
    
    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        
        // 创建唯一 ID
        id = newId();
        
        // 【核心】调用 newUnsafe() 方法创建 unsafe 实例
        unsafe = newUnsafe();
        
        // 创建 Pipeline
        pipeline = newChannelPipeline();
    }
    
    // 抽象方法,由子类实现
    protected abstract AbstractUnsafe newUnsafe();
    
    protected ChannelId newId() {
        return DefaultChannelId.newInstance();
    }
    
    protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }
}

说明

  • unsafe 字段在这里被初始化
  • 调用 newUnsafe() 方法创建实例
  • newUnsafe() 是抽象方法,需要子类实现

关键问题:这里调用的是哪个类的 newUnsafe() 方法?


步骤 7:多态机制 - 实际调用的是哪个 newUnsafe()?

虽然 newUnsafe() 方法在 AbstractChannel 中被调用,但是:

当前对象的实际类型是 NioServerSocketChannel

让我们看看继承链上哪个类实现了 newUnsafe() 方法:

AbstractChannel(定义抽象方法)
protected abstract AbstractUnsafe newUnsafe();
AbstractNioChannel(没有实现)
// 这个类没有实现 newUnsafe() 方法
AbstractNioMessageChannel(实现了!)

位置io.netty.channel.nio.AbstractNioMessageChannel

public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
    
    @Override
    protected AbstractNioUnsafe newUnsafe() {
        // 返回 NioMessageUnsafe 实例
        return new NioMessageUnsafe();
    }
}

找到了! AbstractNioMessageChannel 实现了 newUnsafe() 方法。

NioServerSocketChannel(没有重写)
// 这个类没有重写 newUnsafe() 方法
// 所以使用父类 AbstractNioMessageChannel 的实现

步骤 8:Java 多态机制详解

为什么调用的是 AbstractNioMessageChannel.newUnsafe()

这是 Java 的多态机制决定的。让我们用一个简单的例子说明:

// 类比例子
class Animal {
    void init() {
        sound = makeSound();  // 调用抽象方法
    }
    abstract String makeSound();
}

class Dog extends Animal {
    @Override
    String makeSound() {
        return "汪汪";  // Dog 实现了 makeSound
    }
}

// 创建对象
Animal animal = new Dog();  // 实际类型是 Dog
// 虽然 init() 方法在 Animal 类中
// 但 makeSound() 调用的是 Dog 的实现

对应到 Netty:

// 创建对象
new NioServerSocketChannel();

// 调用链路
NioServerSocketChannel 构造
  ↓
AbstractNioMessageChannel 构造
  ↓
AbstractNioChannel 构造
  ↓
AbstractChannel 构造
  ↓
unsafe = newUnsafe();  // 在 AbstractChannel 中调用

关键点

  1. 虽然 newUnsafe()AbstractChannel 中被调用
  2. 但当前对象的实际类型是 NioServerSocketChannel
  3. Java 虚拟机会从实际类型开始,向上查找 newUnsafe() 的实现
  4. 查找顺序:
    • NioServerSocketChannel → 没有实现
    • AbstractNioMessageChannel找到了!
  5. 所以调用的是 AbstractNioMessageChannel.newUnsafe()

步骤 9:NioMessageUnsafe 是什么

位置io.netty.channel.nio.AbstractNioMessageChannel

public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
    
    @Override
    protected AbstractNioUnsafe newUnsafe() {
        return new NioMessageUnsafe();
    }
    
    // NioMessageUnsafe 是 AbstractNioMessageChannel 的内部类
    private final class NioMessageUnsafe extends AbstractNioUnsafe {
        
        private final List<Object> readBuf = new ArrayList<Object>();
        
        @Override
        public void read() {
            assert eventLoop().inEventLoop();
            final ChannelConfig config = config();
            final ChannelPipeline pipeline = pipeline();
            final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
            allocHandle.reset(config);
            
            boolean closed = false;
            Throwable exception = null;
            try {
                try {
                    do {
                        // 【核心】调用 doReadMessages 接受新连接
                        int localRead = doReadMessages(readBuf);
                        if (localRead == 0) {
                            break;
                        }
                        if (localRead < 0) {
                            closed = true;
                            break;
                        }
                        allocHandle.incMessagesRead(localRead);
                    } while (allocHandle.continueReading());
                } catch (Throwable t) {
                    exception = t;
                }
                
                int size = readBuf.size();
                for (int i = 0; i < size; i++) {
                    readPending = false;
                    // 【核心】触发 channelRead 事件,传递新的 SocketChannel
                    pipeline.fireChannelRead(readBuf.get(i));
                }
                readBuf.clear();
                allocHandle.readComplete();
                pipeline.fireChannelReadComplete();
                
                // ... 异常处理和关闭逻辑
            } finally {
                // ...
            }
        }
    }
    
    // 由子类实现,用于接受新连接
    protected abstract int doReadMessages(List<Object> buf) throws Exception;
}

说明

  • NioMessageUnsafeAbstractNioMessageChannel 的内部类
  • read() 方法的核心功能:
    1. 调用 doReadMessages() 接受新连接
    2. 将新连接(NioSocketChannel)添加到 readBuf
    3. 触发 channelRead 事件,传递新连接

完整调用链路图

new NioServerSocketChannel()
    ↓
NioServerSocketChannel()
    ↓
NioServerSocketChannel(ServerSocketChannel)
    ↓
super(null, channel, OP_ACCEPT)
    ↓
AbstractNioMessageChannel(parent, ch, readInterestOp)
    ↓
super(parent, ch, readInterestOp)
    ↓
AbstractNioChannel(parent, ch, readInterestOp)
    ↓
super(parent)
    ↓
AbstractChannel(parent)
    ↓
unsafe = newUnsafe()  ← 在这里调用
    ↓
【多态机制】查找实际类型的 newUnsafe() 实现
    ↓
NioServerSocketChannel.newUnsafe()? → 没有
    ↓
AbstractNioMessageChannel.newUnsafe()? → 找到了!
    ↓
return new NioMessageUnsafe()
    ↓
unsafe 字段被赋值为 NioMessageUnsafe 实例

为什么是 NioMessageUnsafe?

设计原因

NioServerSocketChannel 的工作是接受新连接,不是读取字节数据。

  • 每次 read() 操作返回的是一个对象(新的 NioSocketChannel
  • 不是返回字节数据
  • 所以使用 NioMessageUnsafe(处理"消息/对象")

对比

Channel 类型Unsafe 类型read() 方法作用
NioServerSocketChannelNioMessageUnsafe接受新连接,返回 NioSocketChannel 对象
NioSocketChannelNioByteUnsafe读取字节数据,返回 ByteBuf

总结

  1. unsafe 字段在哪里定义?

    • AbstractChannel 中定义
  2. unsafe 字段在哪里初始化?

    • AbstractChannel 构造方法中,通过调用 newUnsafe() 初始化
  3. 为什么调用的是 AbstractNioMessageChannel.newUnsafe()

    • 因为 Java 多态机制
    • 虽然调用代码在 AbstractChannel
    • 但实际对象类型是 NioServerSocketChannel
    • JVM 从实际类型开始向上查找 newUnsafe() 的实现
    • AbstractNioMessageChannel 中找到了实现
  4. unsafe 的实际类型是什么?

    • NioMessageUnsafe
  5. 为什么是这个类型?

    • 因为 NioServerSocketChannel 的工作是接受新连接(返回对象)
    • 不是读取字节数据
    • 所以使用 NioMessageUnsafe(处理消息/对象)

核心答案:服务端的 unsafeNioMessageUnsafe 实例,由 Java 多态机制决定调用 AbstractNioMessageChannel.newUnsafe() 方法创建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值