深度解析dubbo网络传输层Channel

本文基于dubbo v2.6.x

1. Channel

Channel可以理解为通道,两端传输数据的一个通道。在这里我们介绍的Channel是dubbo的channel,是dubbo对于各种io框架数据通道的封装。它主要提供了操作属性的方法与获取远端地址的方法

public interface Channel extends Endpoint {
    InetSocketAddress getRemoteAddress();//获取远程地址
    boolean isConnected();//是否已连接
    boolean hasAttribute(String key);//根据key判断属性值是否存在
    Object getAttribute(String key);//根据key获取属性值
    void setAttribute(String key, Object value);//设置属性值
    void removeAttribute(String key);//移除属性值
}

我们看到它这几个操作属性值的方法,包括 设置,获取,移除,判断存在,同时判断连接状态与获取远端地址。还继承Endpoint 接口,
Endpoint表示端点的意思,客户端,服务端都可以认为是一个端点,Endpoint主要抽象了端点的关闭,发送消息,获取本端点的地址等。
接下来我们来看下它的UML类图
在这里插入图片描述
我们可以将Channel的实现分为三类,一是左边红框的,该实现主要是在网络传输层针对各io框架提供的Channel与dubbo的Channel一个转换适配,中间ExchangeChannel 这部分的实现主要是信息交换层对Channel的封装,右侧则就是Client了,我们在《深度解析dubbo网络传输层Client》解析Client的时候,曾经说过Client也是Channel,因为继承该接口。
本文主要是解析左侧红框网络传输层的Channel实现。

2.AbstractChannel

AbstractChannel是Channel的一个抽象实现类,其实它自己并没有实现啥功能,重要的是它继承AbstractPeer 这个抽象类,该抽象类主要是维护着URL与ChannelHandler,同时维护了关闭状态。AbstractPeer实现了ChannelHandler接口,然后将connected,disconnected,sent,received,caught 方法,并将这些交给交给维护的ChannelHandler对象处理。
在这里插入图片描述
我们看到它确实没有实现啥功能,唯一一个send发送消息的方法 就是判断下关闭状态。我们从Channel的UML类图中可以看到它的实现有GrizzlyChannel,MinaChannel,netty3与netty4的不同实现NettyChannel。接下来我们来看下这个netty4的NettyChannel实现。

3.NettyChannel

NettyChannel 可以理解为一个适配类,然后将netty框架自己的Channel 包装成dubbo的Channel,使其具有通用性。
先来看下它的静态成员与成员变量:

// 做缓存channel缓存
private static final ConcurrentMap<Channel, NettyChannel> channelMap = new ConcurrentHashMap<Channel, NettyChannel>();
//通道
private final Channel channel;
//属性
private final Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();

channelMap 这个是个静态成员,它主要维护了 netty Channel 与dubbo Channel的一个对应关系。
channel 这个就是netty4 框架的Channel。
attributes 这个map就是属性与属性值。
接下来看下构造方法:

private NettyChannel(Channel channel, URL url, ChannelHandler handler) {
    super(url, handler);
    if (channel == null) {
        throw new IllegalArgumentException("netty channel == null;");
    }
    this.channel = channel;
}

可以看到它这个构造方法是个私有的,也就是只有本类的方法才能创建,我们来看下它是怎样创建的。

static NettyChannel getOrAddChannel(Channel ch, URL url, ChannelHandler handler) {
    if (ch == null) {
        return null;
    }
    //根据channel 获取NettyChannel
    NettyChannel ret = channelMap.get(ch);
    if (ret == null) {// 没有存在就创建
        NettyChannel nettyChannel = new NettyChannel(ch, url, handler);
        if (ch.isActive()) {// channel 是活的 就进行缓存 key 是channel 然后value是 nettychannel
            ret = channelMap.putIfAbsent(ch, nettyChannel);
        }
        if (ret == null) {
            ret = nettyChannel;
        }
    }
    return ret;
}

先根据netty的Channel从channelMap 这个缓存获取NettyChannel 对象,如果没有的话就创建,然后塞到这个缓存中,最后将这个NettyChannel返回。

static void removeChannelIfDisconnected(Channel ch) {
   if (ch != null && !ch.isActive()) {
       channelMap.remove(ch);
   }
}

这个移除方法就是判断传过来的netty Channel不是空并且断开,就从这个缓存channelMap 中移除。
接下来看下它的操作属性的实现:

/**
 * 属性是否存在
 * @param key key.
 * @return
 */
@Override
public boolean hasAttribute(String key) {
    return attributes.containsKey(key);
}
/**
 * 根据key获取属性值
 * @param key key.
 * @return
 */
@Override
public Object getAttribute(String key) {
    return attributes.get(key);
}
/**
 * 设置属性
 * @param key   key.
 * @param value value.
 */
@Override
public void setAttribute(String key, Object value) {
    if (value == null) { // The null value unallowed in the ConcurrentHashMap.
        attributes.remove(key);
    } else {
        attributes.put(key, value);
    }
}
/**
 * 移除属性
 * @param key key.
 */
@Override
public void removeAttribute(String key) {
    attributes.remove(key);
}

其实这几个操作属性的方法,其实就是操作attributes 这个存储属性的map。
最后来看下send发送消息的方法:

/**
 * 发送 消息
 * @param message
 * @param sent
 * @throws RemotingException
 */
@Override
public void send(Object message, boolean sent) throws RemotingException {
    super.send(message, sent);// 这里调用父类就是为了判断 这个channel有没有关闭
    boolean success = true;
    int timeout = 0;
    try {// netty channel 发送 得到一个channelfuture
        ChannelFuture future = channel.writeAndFlush(message);
        if (sent) {
            // 默认超时时间 1s
            timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
            success = future.await(timeout);
        }
        Throwable cause = future.cause();
        if (cause != null) {// 如果有异常 抛出异常
            throw cause;
        }
    } catch (Throwable e) {
        throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e);
    }
    /**
     * 没有成功抛出异常
     */
    if (!success) {
        throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress()
                + "in timeout(" + timeout + "ms) limit");
    }
}

在send方法中,先调用父类的send方法检查channel是否关闭,然后调用netty channel 进行发送消息,如果是需要sent反馈的话,就获取配置的timeout 超时时间,缺省是1s,等待timeout超时时间获取发送状态,如果发送状态是false,或者出现了异常,则会抛出异常。

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页