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 {
Attribute attr(AttributeKey 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 KEY_USER_ID = AttributeKey.valueOf("userId");
int userId = channel.attr(KEY_USER_ID).get();
UniqueName实际上是靠传入构造函数的一个map来保证name的唯一性:
@Deprecated
public class UniqueName implements Comparable {
private static final AtomicInteger nextId = new AtomicInteger();
private final int id;
private final String name;
public UniqueName(ConcurrentMap 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 extends UniqueName {
private static final ConcurrentMap names = PlatformDependent.newConcurrentHashMap();
@SuppressWarnings("deprecation")
public static AttributeKey valueOf(String name) {
return new AttributeKey(name);
}
@Deprecated
public AttributeKey(String name) {
super(names, name);
}
}
Attribute接口除了有必须的get()和set()和remove()方法外,还有几个原子方法:
public interface Attribute {
AttributeKey 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 updater =
AtomicReferenceFieldUpdater.newUpdater(DefaultAttributeMap.class, Map.class, "map");
// Initialize lazily to reduce memory consumption; updated by AtomicReferenceFieldUpdater above.
@SuppressWarnings("UnusedDeclaration")
private volatile Map, Attribute>> map;
@Override
public Attribute attr(AttributeKey key) {
Map, Attribute>> map = this.map;
if (map == null) {
// Not using ConcurrentHashMap due to high memory consumption.
map = new IdentityHashMap, Attribute>>(2);
if (!updater.compareAndSet(this, null, map)) {
map = this.map;
}
}
synchronized (map) {
@SuppressWarnings("unchecked")
Attribute attr = (Attribute) map.get(key);
if (attr == null) {
attr = new DefaultAttribute(map, key);
map.put(key, attr);
}
return attr;
}
}
...
}
可以看到:
最后,DefaultAttribute通过继承AtomicReference获得了原子操作能力:
public class DefaultAttributeMap implements AttributeMap {
private static final class DefaultAttribute extends AtomicReference implements Attribute {
private static final long serialVersionUID = -2661411462200283011L;
private final Map, Attribute>> map;
private final AttributeKey key;
DefaultAttribute(Map, Attribute>> map, AttributeKey key) {
this.map = map;
this.key = key;
}
@Override
public AttributeKey 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的内部结构: