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