Netty常量池(1)

public static final ChannelOption<Integer> SO_RCVBUF = valueOf("SO_RCVBUF"), 通过valueOf作为
入口进行创建, 可以联想到, 这个SO_RCVBUF就是常量池中ConcurrentMap的key, 与此同时会创建一个
ChannelOption, 这个ChannelOption的name也是SO_RCVBUF, 我们再来看看ConstantPool的valueOf源码

public T valueOf(String name) {
    checkNotNullAndNotEmpty(name);
    return getOrCreate(name);
}

private T getOrCreate(String name) {
    T constant = constants.get(name);
    if (constant == null) {
        final T tempConstant = newConstant(nextId(), name);
        constant = constants.putIfAbsent(name, tempConstant);
        if (constant == null) {
            return tempConstant;
        }
    }

    return constant;
}
 其实很简单, constants就是那个ConcurrentMap, 通过key为SO_RCVBUF去这个map查找对应的ChannelOption
    如果没找到, 那么就调用newConstant创建一个该常量, 并且放入到ConcurrentMap中, newConstant由子类来
    觉得创建的是哪个类型的常量, ChannelOption有一个匿名内部类是ConstantPool的子类, 之前我们也看过了,
    其创建的是ChannelOption

总结:
    任何配置都是一个key-value, ConstantPool用来保存任何配置中的key的对象表示形式, 其实就是用一个
    ConcurrentMap来保存的, ConstantPool的子类来觉得这个Map中的value存储的是什么类型值, Channel的配置
    对应的key用ChannelOption来表示, ChannelOption里面有一个name用来存储这个配置的字符串表示, 
    ChannelOption中利用一个匿名内部类继承于ConstantPool, 利用泛型指明了ConcurrentMap中保存的是
    ChannelOption类型, 对于Channel中的SO_RCVBUF这个配置来说, 会创建一个ChannelOption, 
    ChannelOption中的name就是SO_RCVBUF, 与此同时将这个ChannelOption保存到常量池中



![](https://upload-images.jianshu.io/upload_images/24195226-6fc73014cc427b7f.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



### ChannelConfig

ChannelConfig, 故名思意了, 保存了Channel的配置, 比如说接收缓冲区的大小等, Netty中的Channel有很多类型,
对于Nio的是NioServerSocketChannel以及NioSocketChannel, 对于Bio的OioServerSocketChannel以及
OioSocketChannel, 不同类型的Channel配置自然就不一样, 如下图所示, 就是ChannelConfig的简单类图, 可以清
晰的看到, 在红线的两边刚好分为了两块, 一个是Nio的ChannelConfig, 一个是Bio的ChannelConfig, 都是用来存
储对应的Channel的配置信息的, 那到底怎么存呢?其实也没那么复杂, 就用一个Map存就好了, 比如说对于服务端需要
存储SO_RCVBUF这个配置信息, 正常情况应该是map.put( "SO_RCVBUF", 1024 ), 但是在Netty中, 用
ChannelOption对象的方式来表示这个配置的key, 于是就变成了map.put( ChannelOption.SO_RCVBUF, 1024 ),
到此为止, 我们就将ChannelConfig - ChannelOption - ConstantPool的关系给描述完毕了


![](https://upload-images.jianshu.io/upload_images/24195226-74f6a66767c79b4d.image?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



### DefaultAttributeMap及AttributeKey

前面我们熟悉了ConstantPool与ChannelOption之间的关系, 以及ChannelConfig与ChannelOption之间的关系, 此
时再来看ConstantPool-AttributeKey-DefaultAttributeMap就会非常轻松了

我们在使用Netty的时候, 对ChannelHandler肯定是不会陌生的, 一个客户端与服务器的数据交互, 当数据到达了服
务端Netty程序的时候, 必然是通过多个ChannelHandler进行处理的, 比如先由LengthFieldPrepender这个
ChannelHandler对数据进行解码, 然后传给下一层级的ChannelHandler, 当数据写回客户端的时候, 同样会经过多
个ChannelHandler, 最后经过LengthFieldBasedFrameDecoder这个ChannelHandler进行编码并write回客户端,
这一整个生命周期中, 都是对一个SocketChannel进行操作, 那么假设想要从前一个ChannelHandler传递一些数据到
后一个ChannelHandler, 就需要将放置的数据存在到一个地方中, 所有的ChannelHandler都能够访问这块空间

DefaultAttributeMap就是这一块空间, 我们使用的NioServerSocketChannel就是这个类的子类, 
NioServerSocketChannel之后的文章我们会进行分析, 那知道这两者关系的情况下, 我们就可以想到, 所有的
ChannelHandler中, 获取到对应的Channel, 就能访问这个Channel的共享空间DefaultAttributeMap, 可以往里面
写入key-value, 或者根据key读取value, 而这个key就是AttributeKey, value是我们自定义的值

先来说说这个AttributeKey吧, 跟ChannelOption是类似的, ChannelOption用来表示配置的key, 而AttributeKey
则是用来表示DefaultAttributeMap中的key, 联想ChannelOption, 可以知道AttributeKey中一定也会有一个匿名
内部类实现了ConstantPool接口, 即:
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);
        }
    };
}
再来看看DefaultAttributeMap, 虽然说是Map, 其实里面用的确实数组来存储值的, 值为一个个的
AtomicReference对象, 利用一个AtomicReferenceArray来存储这些一个个的AtomicReference对象, 我们先来看
看DefaultAttributeMap的源码:

public class DefaultAttributeMap implements AttributeMap {
private volatile AtomicReferenceArray<DefaultAttribute<?>> attributes;

private static int index(AttributeKey<?> key) {
    return key.id() & MASK;
}

// 为了让大家知道这里面做了什么事情, 简略的大量的代码, 只抽离了核心的两行
public <T> Attribute<T> attr(AttributeKey<T> key) {
    int i = index(key);
    DefaultAttribute<?> head = attributes.get(i);
}

private static final class DefaultAttribute<T> 
                                    extends AtomicReference<T> implements Attribute<T> {

    private final AttributeKey<T> key;
    ..................
}

}

分析:
    这样一看就很清晰了, DefaultAttributeMap中有一个AtomicReferenceArray的数组, 里面放置的是一个个的
    DefaultAttribute对象, DefaultAttribute继承了AtomicReference, attr方法就是根据AttributeKey获取
    这个数组中对应的值, 通过AttributeKey的id能够获取索引, 从而取出值, 而DefaultAttributeMap是所有
    Channel的父类, 这些Channel利用DefaultAttributeMap这个类实现了所有ChannelHandler能够共享一块空间
    从而实现了在ChannelHandler执行的过程中能够实现数据的传递


### 总结

ChannelConfig存储Channel的配置, Channel的配置的key为ChannelOption, 为了能够缓存ChannelOption, 引入
了ConstantPool常量池, 为了能够在Channel数据交互处理的生命周期中, 不同的ChannelHandler能够共享空间, 实
现参数的传递等功能, 所有的Channel会继承于DefaultAttributeMap, DefaultAttributeMap利用一个数组来保存
所有的值, 通过AttributeKey来计算索引, AttributeKey跟ChannelOption类似, 也是常量类型
##最后
上一篇:mq修改namesrv和broker启动内存


下一篇:httprunner3源码解读(1)简单介绍源码模块内容