可通过SelectionKey.attach()绑定业务对象,事件处理时用key.attachment()取回;适用于存储会话、缓冲区等通道关联状态,应在注册后或OP_ACCEPT时绑定,避免重复attach。

可以通过 SelectionKey.attach(Object) 方法将自定义业务对象绑定到键上,后续在事件处理(如 OP_READ、OP_WRITE)中通过 key.attachment() 取回,实现通道与业务上下文的关联。
attachment 的作用和适用场景
attachment 是 SelectionKey 提供的一个“挂载点”,用于存储与该通道生命周期一致的业务状态。比如:一个客户端连接对应的会话对象、请求缓冲区、协议解析器、用户身份信息等。它避免了用 Map 显式维护 channel → object 映射,也规避了并发访问 map 的同步开销。
正确设置 attachment 的时机
attachment 应在注册 Channel 到 Selector 后、首次事件触发前完成绑定,常见位置有:
- 调用
channel.register(selector, ops)得到 SelectionKey 后立即 attach - 在
OP_ACCEPT事件中,为新 accept 的 SocketChannel 创建并 attach 新会话对象 - 不要在事件循环中反复 attach(会覆盖),除非明确需要更新上下文
典型使用示例(简化版)
假设处理客户端连接,每个连接需维护自己的读缓冲区和用户 ID:
// 接受新连接时
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
SelectionKey key = client.register(selector, SelectionKey.OP_READ);
// 绑定自定义会话对象
Session session = new Session(client.getRemoteAddress(), ByteBuffer.allocate(1024));
key.attach(session);
// 在 OP_READ 事件中
if (key.isReadable()) {
Session s = (Session) key.attachment(); // 安全取回
ByteBuffer buf = s.buffer;
int n = client.read(buf);
if (n > 0) {
buf.flip();
// 解析业务数据,s.userId 可用于权限判断等
processRequest(buf, s.userId);
}
}
注意事项
类型安全:attach 接收 Object,取回时务必强转,并建议用泛型工具类或封装 key 操作避免 ClassCastException。
线程安全:attachment 本身不保证线程安全;若多线程可能修改同一 key 的 attachment(如同时 OP_READ 和 OP_WRITE),需自行同步或改用不可变对象。
内存泄漏风险:确保在连接关闭时清理相关资源(如释放 ByteBuffer、关闭流),attachment 引用的对象不会自动被回收,需在 key.cancel() 前手动置空或清理。










