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主要抽象了端点的关闭,发送消息,获取本端点的地址等。
public abstract class AbstractChannel extends AbstractPeer implements Channel {
public AbstractChannel(URL url, ChannelHandler handler) {
super(url, handler);
}
@Override
public void send(Object message, boolean sent) throws RemotingException {
if (isClosed()) {
throw new RemotingException(this, "Failed to send message "
+ (message == null ? "" : message.getClass().getName()) + ":" + PayloadDropper.getRequestWithoutData(message)
+ ", cause: Channel closed. channel: " + getLocalAddress() + " -> " + getRemoteAddress());
}
}
@Override
public String toString() {
return getLocalAddress() + " -> " + getRemoteAddress();
}
}
AbstractChannel 继承了AbstractPeer,AbstractPeer实现了ChannelHandler接口,然后将connected,disconnected,sent,received,caught 方法给成员变量
ChannelHandler handler来维护。
在NettyChannel中,构造方法是私有的,提供给getOrAddChannel方法使用,
在getOrAddChannel方法中,netty的Channel从channelMap 这个缓存获取NettyChannel 对象,如果没有的话就创建,然后塞到这个缓存中,最后将这个NettyChannel返回
static NettyChannel getOrAddChannel(org.jboss.netty.channel.Channel ch, URL url, ChannelHandler handler) {
if (ch == null) {
return null;
}
NettyChannel ret = CHANNEL_MAP.get(ch);
if (ret == null) {
NettyChannel nc = new NettyChannel(ch, url, handler);
if (ch.isConnected()) {
ret = CHANNEL_MAP.putIfAbsent(ch, nc);
}
if (ret == null) {
ret = nc;
}
}
return ret;
}
在send方法中,先调用父类的send方法检查channel是否关闭,然后调用netty channel 进行发送消息,如果是需要sent反馈的话,就获取配置的timeout 超时时间,缺省是1s,等待timeout超时时间获取发送状态,如果发送状态是false,或者出现了异常,则会抛出异常。
@Override
public void send(Object message, boolean sent) throws RemotingException {
super.send(message, sent);
boolean success = true;
int timeout = 0;
try {
ChannelFuture future = channel.write(message);
if (sent) {
timeout = getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
success = future.await(timeout);
}
Throwable cause = future.getCause();
if (cause != null) {
throw cause;
}
} catch (Throwable e) {
throw new RemotingException(this, "Failed to send message " + PayloadDropper.getRequestWithoutData(message) + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e);
}
if (!success) {
throw new RemotingException(this, "Failed to send message " + PayloadDropper.getRequestWithoutData(message) + " to " + getRemoteAddress()
+ "in timeout(" + timeout + "ms) limit");
}
}