MINA的IoSession接口定义了一组方法,让我们可以利用IoSession来存储一些数据:
public interface IoSession { getAttribute(Object key) getAttribute(Object key, Object defaultValue) setAttribute(Object key) setAttribute(Object key, Object value) setAttributeIfAbsent(Object key) setAttributeIfAbsent(Object key, Object value) replaceAttribute(Object key, Object oldValue, Object newValue) removeAttribute(Object key) removeAttribute(Object key, Object value) containsAttribute(Object key) getAttributeKeys() }
public interface AttributeMap { <T> Attribute<T> attr(AttributeKey<T> key); }
AttributeMap接口只有一个attr()方法,接收一个AttributeKey类型的key,返回一个Attribute类型的value。按照Javadoc,AttributeMap实现必须是线程安全的。AttributeMap内部结构看起来像下面这样:
答案是所有的Channel和ChannelHandlerContext,如下面的类图所示:
AttributeKey有两个地方值得 一提。第一是AttributeKey是个泛型类,在我看来,这也是Netty相对于MINA的一处改进。在使用IoSession的时候,你必须进行强制类型转换:
int userId = (Integer) ioSession.getAttribute("userId");但是使用AttributeMap却不需要:
AttributeKey<Integer> KEY_USER_ID = AttributeKey.valueOf("userId"); int userId = channel.attr(KEY_USER_ID).get();
UniqueName实际上是靠传入构造函数的一个map来保证name的唯一性:
@Deprecated public class UniqueName implements Comparable<UniqueName> { private static final AtomicInteger nextId = new AtomicInteger(); private final int id; private final String name; public UniqueName(ConcurrentMap<String, Boolean> map, String name, Object... args) { if (map == null) { throw new NullPointerException("map"); } if (name == null) { throw new NullPointerException("name"); } if (args != null && args.length > 0) { validateArgs(args); } if (map.putIfAbsent(name, Boolean.TRUE) != null) { throw new IllegalArgumentException(String.format("'%s' is already in use", name)); } id = nextId.incrementAndGet(); this.name = name; } ... }但是Javadoc说这个类存在跟类加载器相关的问题,所以被废弃了。AttributeKey继承了UniqueName,内部使用ConcurrentHashMap来保证name的唯一性:
public final class AttributeKey<T> extends UniqueName { private static final ConcurrentMap<String, Boolean> names = PlatformDependent.newConcurrentHashMap(); @SuppressWarnings("deprecation") public static <T> AttributeKey<T> valueOf(String name) { return new AttributeKey<T>(name); } @Deprecated public AttributeKey(String name) { super(names, name); } }
Attribute接口除了有必须的get()和set()和remove()方法外,还有几个原子方法:
public interface Attribute<T> { AttributeKey<T> key(); T get(); void set(T value); T getAndSet(T value); T setIfAbsent(T value); T getAndRemove(); boolean compareAndSet(T oldValue, T newValue); void remove(); }
如前面的类图所示,DefaultAttributeMap实现了AttributeMap接口,AbstractChannel和DefaultChannelHandlerContext通过继承DefaultAttributeMap也实现了AttributeMap接口。下面是DefaultAttributeMap的部分代码:
public class DefaultAttributeMap implements AttributeMap { @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater<DefaultAttributeMap, Map> updater = AtomicReferenceFieldUpdater.newUpdater(DefaultAttributeMap.class, Map.class, "map"); // Initialize lazily to reduce memory consumption; updated by AtomicReferenceFieldUpdater above. @SuppressWarnings("UnusedDeclaration") 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. map = new IdentityHashMap<AttributeKey<?>, Attribute<?>>(2); if (!updater.compareAndSet(this, null, map)) { map = this.map; } } 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; } } ... }可以看到:
最后,DefaultAttribute通过继承AtomicReference获得了原子操作能力:
public class DefaultAttributeMap implements AttributeMap { private static final class DefaultAttribute<T> extends AtomicReference<T> implements Attribute<T> { private static final long serialVersionUID = -2661411462200283011L; private final Map<AttributeKey<?>, Attribute<?>> map; private final AttributeKey<T> key; DefaultAttribute(Map<AttributeKey<?>, Attribute<?>> map, AttributeKey<T> key) { this.map = map; this.key = key; } @Override public AttributeKey<T> key() { return key; } @Override public T setIfAbsent(T value) { while (!compareAndSet(null, value)) { T old = get(); if (old != null) { return old; } } return null; } @Override public T getAndRemove() { T oldValue = getAndSet(null); remove0(); return oldValue; } @Override public void remove() { set(null); remove0(); } private void remove0() { synchronized (map) { map.remove(key); } } } }下面是DefaultAttributeMap的内部结构: