这几天开始看netty,作些笔记。
netty5文档中 ChannelHandler开始处介绍了attachment的使用,用来保存handler的状态信息
public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
private final AttributeKey<Boolean> auth =
new AttributeKey<Boolean>("auth");
@Override
public void channelRead(ChannelHandlerContext ctx, Integer integer) {
Attribute<Boolean> attr = ctx.getAttr(auth);
//...
}
AttributeKey<T>和Attribute<T>应该就是map中的键值对,而这个map应该绑定在ChannelHandlerContext中。
文档中对ChannelHandlerContext的描述:
A ChannelHandler is provided with a ChannelHandlerContext object. A ChannelHandler is supposed to interact with the ChannelPipeline it belongs to via a context object. Using the context object, the ChannelHandler can pass events upstream or downstream, modify the pipeline dynamically, or store the information (attachment) which is specific to the handler.
一个handler有一个与之对应的context,handler通过这个context对象与pipeline互动,
使用这个上下文对象,可以实现...保存某个handler的信息(attachment)。
查看源码:
DefaultChannelHandlerContext继承了DefaultAttributeMap
final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext{...}
DefaultAttributeMap的实现:
@SuppressWarnings("rawtypes")
private static final AtomicReferenceFieldUpdater<DefaultAttributeMap, Map> updater = AtomicReferenceFieldUpdater.newUpdater(DefaultAttributeMap.class, Map.class, "map");
private volatile Map<AttributeKey<?>, Attribute<?>> map;
@Override
public <T> Attribute<T> attr(AttributeKey<T> key) {
Map<AttributeKey<?>, Attribute<?>> map = this.map;
if (map == null) {
// Not using ConcurrentHashMap due to high memory consumption.
//创建一个初始值为2的IdentityHashMap,控制内存消耗
map = new IdentityHashMap<AttributeKey<?>, Attribute<?>>(2);
if (!updater.compareAndSet(this, null, map)) {
//如果原子更新失败,即执行到这里时map被其它线程赋值,而不是预期的
//null值,那就直接使用当前值
map = this.map;
}
}
//同步块,如果获得的attribute<T>是null,那就创建一个DefaultAttribute<T>
synchronized (map) {
@SuppressWarnings("unchecked")
Attribute<T> attr = (Attribute<T>) map.get(key);
if (attr == null) {
attr = new DefaultAttribute<T>(map, key);
map.put(key, attr);
}
return attr;
}
}
//......
可见作者在此处作了严密的控制,看到这里,心里充满了安全感
另外要注意的是:
因为在 ChannelHandlerContext 中的 AttibuteMap 是绑定在该上下文中的,所以你在某个上下文中定义的 Attribute 在另一个handler的上下文中是看不到的。
Channel 中也实现了 AttributeMap,你可以使用绑定在 Channel 中的 AttributeMap,用来在handler之间传递attachment。
ctx.channel().attr(...)...;