Stores the user-defined attributes which is provided per IoSession. All user-defined attribute accesses in IoSession are forwarded to the instance of IoSessionAttributeMap.
public interface IoSessionAttributeMap {
Object getAttribute(IoSession session, Object key, Object defaultValue);
Object setAttribute(IoSession session, Object key, Object value);
Object setAttributeIfAbsent(IoSession session, Object key, Object value);
Object removeAttribute(IoSession session, Object key);
boolean removeAttribute(IoSession session, Object key, Object value);
boolean replaceAttribute(IoSession session, Object key, Object oldValue, Object newValue);
boolean containsAttribute(IoSession session, Object key);
Set<Object> getAttributeKeys(IoSession session);
void dispose(IoSession session) throws Exception;
}
private static class DefaultIoSessionAttributeMap implements IoSessionAttributeMap {
private final ConcurrentHashMap<Object, Object> attributes = new ConcurrentHashMap<Object, Object>(4);
}
在DefaultIoSessionDataStructureFactory 类中,使用ConcurrentHashMap 来保存用户自定义数据。
public final class AttributeKey implements Serializable {
/** The serial version UID */
private static final long serialVersionUID = -583377473376683096L;
/** The attribute's name */
private final String name;
public AttributeKey(Class<?> source, String name) {
this.name = source.getName() + '.' + name + '@' + Integer.toHexString(this.hashCode());
}
}
使用AttributeKey 作为键。
在看看在netty 中是如何保存用户自定义数据的。
/**
* Holds {@link Attribute}s which can be accessed via {@link AttributeKey}.
*
* Implementations must be Thread-safe.
*/
public interface AttributeMap {
/**
* Get the {@link Attribute} for the given {@link AttributeKey}. This method will never return null, but may return
* an {@link Attribute} which does not have a value set yet.
*/
<T> Attribute<T> attr(AttributeKey<T> key);
/**
* Returns {@code} true if and only if the given {@link Attribute} exists in this {@link AttributeMap}.
*/
<T> boolean hasAttr(AttributeKey<T> key);
}
public class DefaultAttributeMap implements AttributeMap {
@SuppressWarnings("rawtypes")
private static final AtomicReferenceFieldUpdater<DefaultAttributeMap, AtomicReferenceArray> updater;
static {
@SuppressWarnings("rawtypes")
AtomicReferenceFieldUpdater<DefaultAttributeMap, AtomicReferenceArray> referenceFieldUpdater =
PlatformDependent.newAtomicReferenceFieldUpdater(DefaultAttributeMap.class, "attributes");
if (referenceFieldUpdater == null) {
referenceFieldUpdater = AtomicReferenceFieldUpdater
.newUpdater(DefaultAttributeMap.class, AtomicReferenceArray.class, "attributes");
}
updater = referenceFieldUpdater;
}
private static final int BUCKET_SIZE = 4;
private static final int MASK = BUCKET_SIZE - 1;
// Initialize lazily to reduce memory consumption; updated by AtomicReferenceFieldUpdater above.
@SuppressWarnings("UnusedDeclaration")
private volatile AtomicReferenceArray<DefaultAttribute<?>> attributes;
}
在Netty中默认AttributeMap是线程安全的,当AttributeMap被多个线程访问时,可以做到线程安全。
/**
* Key which can be used to access {@link Attribute} out of the {@link AttributeMap}. Be aware that it is not be
* possible to have multiple keys with the same name.
*
* @param <T> the type of the {@link Attribute} which can be accessed via this {@link AttributeKey}.
*/
@SuppressWarnings("UnusedDeclaration") // 'T' is used only at compile time
public final class AttributeKey<T> extends AbstractConstant<AttributeKey<T>> {
private static final ConstantPool<AttributeKey<Object>> pool = new ConstantPool<AttributeKey<Object>>() {
@Override
protected AttributeKey<Object> newConstant(int id, String name) {
return new AttributeKey<Object>(id, name);
}
};
/**
* Returns the singleton instance of the {@link AttributeKey} which has the specified {@code name}.
*/
@SuppressWarnings("unchecked")
public static <T> AttributeKey<T> valueOf(String name) {
return (AttributeKey<T>) pool.valueOf(name);
}
/**
* Returns {@code true} if a {@link AttributeKey} exists for the given {@code name}.
*/
public static boolean exists(String name) {
return pool.exists(name);
}
/**
* Creates a new {@link AttributeKey} for the given {@param name} or fail with an
* {@link IllegalArgumentException} if a {@link AttributeKey} for the given {@param name} exists.
*/
@SuppressWarnings("unchecked")
public static <T> AttributeKey<T> newInstance(String name) {
return (AttributeKey<T>) pool.newInstance(name);
}
@SuppressWarnings("unchecked")
public static <T> AttributeKey<T> valueOf(Class<?> firstNameComponent, String secondNameComponent) {
return (AttributeKey<T>) pool.valueOf(firstNameComponent, secondNameComponent);
}
private AttributeKey(int id, String name) {
super(id, name);
}
}
/**
* An attribute which allows to store a value reference. It may be updated atomically and so is thread-safe.
*
* @param <T> the type of the value it holds.
*/
public interface Attribute<T> {
/**
* Returns the key of this attribute.
*/
AttributeKey<T> key();
/**
* Returns the current value, which may be {@code null}
*/
T get();
/**
* Sets the value
*/
void set(T value);
/**
* Atomically sets to the given value and returns the old value which may be {@code null} if non was set before.
*/
T getAndSet(T value);
/**
* Atomically sets to the given value if this {@link Attribute}'s value is {@code null}.
* If it was not possible to set the value as it contains a value it will just return the current value.
*/
T setIfAbsent(T value);
/**
* Removes this attribute from the {@link AttributeMap} and returns the old value. Subsequent {@link #get()}
* calls will return {@code null}.
*
* If you only want to return the old value and clear the {@link Attribute} while still keep it in
* {@link AttributeMap} use {@link #getAndSet(Object)} with a value of {@code null}.
*/
T getAndRemove();
/**
* Atomically sets the value to the given updated value if the current value == the expected value.
* If it the set was successful it returns {@code true} otherwise {@code false}.
*/
boolean compareAndSet(T oldValue, T newValue);
/**
* Removes this attribute from the {@link AttributeMap}. Subsequent {@link #get()} calls will return @{code null}.
*
* If you only want to remove the value and clear the {@link Attribute} while still keep it in
* {@link AttributeMap} use {@link #set(Object)} with a value of {@code null}.
*/
void remove();
}
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
}
所有NioChannel的抽象基类
public abstract class AbstractNioChannel extends AbstractChannel {
}
所有NioByteChannel的抽象基类
public abstract class AbstractNioByteChannel extends AbstractNioChannel {
}
public class NioServerSocketChannel extends AbstractNioMessageChannel
implements io.netty.channel.socket.ServerSocketChannel {
}
public class NioSocketChannel extends AbstractNioByteChannel implements io.netty.channel.socket.SocketChannel {
}
从整体的设计与实现,每一次Netty都是在apache mina 之上的提升和优化, 也许会更加的简单方便。可以是因为先入为主的原因,总感觉apache mina实现的更加简单,容易上手学习。