Netty常量池

再往后, 要配置Channel, 那么就出现了ChannelOption, 要配置数据库就可能会出现DatabaseOption(这一个
是为了让大家更好的理解常量的含义, 笔者臆想的)
于是ChannelOption表示用于Channel配置信息中的key, 我们看到这个ChannelOption的源码, 一开始出现了
一个pool, 池子, 就是本文的核心主题, 常量池, 这个池子的作用是用来保存常量的, 假设我有许多的Channel
配置, 那么我自然就需要有许多的ChannelOption, 由于配置的key一定是固定的, 那么在使用的时候, 如果要
更改配置信息, 总不能每次都new一个ChannelOption来表示配置信息的key吧, 于是, 这些key就被保存到了常量
池中, ConstantPool就是用来保存这些配置对应的key的, ConstantPool是一个抽象类, 里面就一个
ConcurrentMap来保存, ConcurrentMap的key一定是字符串, value是泛型, 泛型为ChannelOption的时候, 表
示这个常量池中保存的是ChannleOption, 泛型为DatabaseOption, 表示这个常量池中保存的是
DatabaseOption, 这个应该好理解, 不同类型的常量对象, 只需要在其类中创建一个ConstantPool就好了, 父
类的ConcurrentMap是公共需要的, 但是ConcurrentMap里面存的值却需要子类来定义, 同时实现newConstant
方法表示这个池子中常量的创建, 不知道说到这里大家会不会觉得有点绕, 我们以SO_RCVBUF这个ChannelOption
的创建过程及存储过程的源码进行一下分析吧
    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保存到常量池中

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的关系给描述完毕了

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;
        ..................
    }
}

分析:
rence implements Attribute {

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

}

分析:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值