AbstractChannel和AbstractUnsafe抽象类
io.netty.channel.AbstractChannel
从本章开始,会有大量的篇幅涉及到代码分析。为了能够清晰简洁的地说明代码的结构和功能,我会用代码注释+独立段落的方式加以呈现。 所以,为你能更好地理解代码,请不要忽略代码中黑体字注释。
AbstractChannel和AbstractUnsafe之间的关系
AbstractChannel实现了Channel接口,AbstractUnsafe实现了Unsafe。这两个类是抽象类,他们实现了Channel和Unsafe的绝大部分接口。在AbstractChannel的实现中,每个方法都会直接或间接调用Unsafe对应的同名方法。所有的inbound和outbound方法都是通过pipeline间接调用,其他的辅助方法直接使用unsafe实例调用。pipline和unsafe实例在AbstractChannel的构造方法创建:
protected AbstractChannel(Channel parent) {
this.parent = parent;
unsafe = newUnsafe(); //AbstractChannel没有实现这个方法
pipeline = newChannelPipeline(); // newChannelPipline的实现 return new DefaultChannelPipeline(this);
}
直接调用的例子:
@Override
public SocketAddress localAddres) {
SocketAddress localAddress = this.localAddress;
if (localAddress == null) {
try {
//这里直接调用了Unsafe的localAddress()方法
this.localAddress = localAddress = unsafe().localAddress();
} catch (Throwable t) {
// Sometimes fails on a closed socket in Windows.
return null;
}
}
return localAddress;
}
间接调用的例子
@Override
public ChannelFuture bind(SocketAddress localAddress) {
return pipeline.bind(localAddress); //通过pipline间接调用Unsafe的bind方法
}
关于pipline是怎样调用Unsafe方法的,会在后面的Pipline相关章节详细分析,这里只需记住。pipeline所有方法调用最终都会(如果没有改变ChannelContextHandler的默认实现)通过使用newUnsafe创建的Unsafe实例调用Unsafe的同名方法(如果有的话)。
netty给出这一对Abstract实现有两个目的:
- 进一步明确接口的语意。
- 简化Channel接口的实现。
下面来具体看一下AbstractUnsafe的主要方法实现。
AbstractUnsafe的重要实现
register实现
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
if (eventLoop == null) {
throw new NullPointerException("eventLoop");
}
if (isRegistered()) { //检查是否已经注册, 避免重复只需注册动作。
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
if (!isCompatible(eventLoop)) {//检查eventloop是否满足Channel的要求,由子类实现
promise.setFailure(
new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
}
//设置Channel的EventLoop实例
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) { //检查是否在当前线程中,如果是,直接调用
register0(promise);
} else {
//如果不是,把register0包装到runnable中放到eventloop中调用。
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
logger.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
这个方法的实现为我们展示了netty使用I/O线程的一般套路
if(eventLoop.inEventLoop()){
doSomething();
}else{
eventLoop.execute(new Runnable(){
@Override
public void run() {
doSomething();
}
});
}
对于某个需要放到I/O线性中执行的方法,先检查当前线程是不是I/O线程,是就直接执行,不是就把它包装到Ruannable中放到eventLoop中执行。
register的功能总结一句话就是调用register0, 下面看看register0的实现。
private void register0(ChannelPromise promise) {
try {
// check if the channel is still open as it could be closed in the mean time when the register
// call was outside of the eventLoop
//确保promise没有被取消同时Channel没有被关闭才能执行后面的动作
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister(); //执行真正的register操作,留改子类实现