转自:http://blog.csdn.net/zxhoo/article/details/17964353
前面有一篇文章分析过Bootstrap类如何引导NioSocketChannel。上篇文章简单讨论了一下Channel接口的方法,知道有四个方法用来查询Channel的状态:isOpen()、isRegistered()、isActive()和isWritable()。这篇文章结合Bootstrap分析一下前三个方法,看看NioSocketChannel是如何到达这三个状态的。
Channel继承层次图
分析上面提到的三个状态的时候,会去看Channel继承层次里某些类的代码,为了方便参考,我画了一张(不太严格的)UML类图,如下所示:
open状态
先从isOpen()方法入手,isOpen()方法是在AbstractNioChannel抽象类里实现的,下面是这个类的关键代码:
- public abstract class AbstractNioChannel extends AbstractChannel {
- ...
- private final SelectableChannel ch;
- ...
- @Override
- public boolean isOpen() {
- return ch.isOpen();
- }
- ...
- }
- Bootstrap.connect(String inetHost, int inetPort)
- -> Bootstrap.doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress)
- -> AbstractBootstrap.initAndRegister()
- -> BootstrapChannelFactory.newChannel()
- -> NioSocketChannel()
- -> NioSocketChannel.newSocket()
- -> SocketChannel.open()
- // AbstractBootstrap.java
- final ChannelFuture initAndRegister() {
- final Channel channel = channelFactory().newChannel();
- try {
- init(channel);
- } catch (Throwable t) {
- channel.unsafe().closeForcibly();
- return channel.newFailedFuture(t);
- }
- ChannelPromise regPromise = channel.newPromise();
- group().register(channel, regPromise);
- ...
- return regPromise;
- }
registered状态
为了证明上面的猜测,我们从NioEventLoopGroup.register()方法接着看代码。NioEventLoopGroup并没有实现register()方法,真正的实现是在它的超类MultithreadEventLoopGroup里:
- // MultithreadEventLoopGroup.java
- @Override
- public ChannelFuture register(Channel channel, ChannelPromise promise) {
- return next().register(channel, promise);
- }
- // SingleThreadEventLoop.java
- @Override
- public ChannelFuture register(final Channel channel, final ChannelPromise promise) {
- ...
- channel.unsafe().register(this, promise);
- return promise;
- }
- // AbstractChannel.java
- @Override
- public boolean isRegistered() {
- return registered;
- }
active状态
还是先看看isActive()方法是如何实现的(在NioSocketChannel里):
- // NioSocketChannel.java
- @Override
- public boolean isActive() {
- SocketChannel ch = javaChannel();
- return ch.isOpen() && ch.isConnected();
- }
- Bootstrap.connect(String inetHost, int inetPort)
- -> Bootstrap.doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress)
- -> AbstractBootstrap.initAndRegister()
- Bootstrap.doConnect0(...)
- -> Channel.connect(SocketAddress remoteAddress, ChannelPromise promise
- // AbstractChannel.java
- @Override
- public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
- return pipeline.connect(remoteAddress, promise);
- }
- // DefaultChannelPipeline.java
- @Override
- public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
- return tail.connect(remoteAddress, promise);
- }
- // DefaultChannelHandlerContext.java
- @Override
- public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
- return connect(remoteAddress, null, promise);
- }
- @Override
- public ChannelFuture connect(final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
- ...
- final DefaultChannelHandlerContext next = findContextOutbound();
- EventExecutor executor = next.executor();
- if (executor.inEventLoop()) {
- next.invokeConnect(remoteAddress, localAddress, promise);
- } else {
- safeExecute(executor, new Runnable() {
- @Override
- public void run() {
- next.invokeConnect(remoteAddress, localAddress, promise);
- }
- }, promise, null);
- }
- return promise;
- }
- private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
- try {
- ((ChannelOutboundHandler) handler).connect(this, remoteAddress, localAddress, promise);
- } catch (Throwable t) {
- notifyOutboundHandlerException(t, promise);
- }
- }
- // DefaultChannelPipeline.java
- static final class HeadHandler implements ChannelOutboundHandler {
- protected final Unsafe unsafe;
- protected HeadHandler(Unsafe unsafe) {
- this.unsafe = unsafe;
- }
- ...
- @Override
- public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
- unsafe.connect(remoteAddress, localAddress, promise);
- }
- ...
- }
- public DefaultChannelPipeline(AbstractChannel channel) {
- ...
- HeadHandler headHandler = new HeadHandler(channel.unsafe());
- head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);
- ...
- }
- // NioSocketChannel.java
- @Override
- protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
- if (localAddress != null) {
- javaChannel().socket().bind(localAddress);
- }
- boolean success = false;
- try {
- boolean connected = javaChannel().connect(remoteAddress);
- if (!connected) {
- selectionKey().interestOps(SelectionKey.OP_CONNECT);
- }
- success = true;
- return connected;
- } finally {
- if (!success) {
- doClose();
- }
- }
- }
结论
代码分析的很复杂,但结论很简单:被Bootstrap引导的NioSocketChannel在构造好之后就进入了open状态,之后通过把自己注册进EventLoop进入registered状态,接着连接服务器进入active状态。