MyException - 我的异常网
当前位置:我的异常网» 开源软件 » netty Inboudn/Outbound通路Invoker

netty Inboudn/Outbound通路Invoker

www.MyException.Cn  网友分享于:2013-09-03  浏览:0次
netty Inboudn/Outbound通道Invoker
Netty 通道处理器ChannelHandler和适配器定义ChannelHandlerAdapter:http://donald-draper.iteye.com/blog/2386891
Netty Inbound/Outbound通道处理器定义:http://donald-draper.iteye.com/blog/2387019
netty 简单Inbound通道处理器(SimpleChannelInboundHandler):http://donald-draper.iteye.com/blog/2387772
netty 消息编码器-MessageToByteEncoder:http://donald-draper.iteye.com/blog/2387832
netty 消息解码器-ByteToMessageDecoder:http://donald-draper.iteye.com/blog/2388088
引言:
前面几篇文章我们看了Netty通道处理器,在分析的过程中我们经常会遇到一个概念为Channel管道线,只知道与通道处理器上下文关联的通道处理器存放在Channel管道线,但一直不知道管道线具体是如何工作的,从今天起,我们将揭开Channel管道线的面纱。
我先从Netty服务端实例代码开始看起,服务端代码有这么一段:
 EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
	//ServerBootstrap,用于配置服务端,一般为ServerSocket通道
    ServerBootstrap serverBoot = new ServerBootstrap(); 
    serverBoot.group(bossGroup, workerGroup)
     .channel(NioServerSocketChannel.class) 
     .childHandler(new ChannelInitializer<SocketChannel>() { 
         @Override
         public void initChannel(SocketChannel ch) throws Exception {
        	//添加通道处理器到通道关联的管道,准确的中文翻译为管道线, 此管道线与Mina中过滤链十分相似,
        	//ChannelInitializer用于配置通道的管道线,ChannelPipeline
        	 ChannelPipeline pipeline = ch.pipeline();
             if (sslCtx != null) {
            	 pipeline.addLast(sslCtx.newHandler(ch.alloc()));
             }
             pipeline.addLast(new LoggingHandler(LogLevel.INFO));
             pipeline.addLast(new EchoServerHandler());
         }
     })
     .option(ChannelOption.SO_BACKLOG, 128)//socket监听器连接队列大小、
     .childOption(ChannelOption.SO_KEEPALIVE, true); //保活,此配置针对ServerSocket通道接收连接产生的Socket通道
    InetSocketAddress inetSocketAddress = new InetSocketAddress(ip,port);
    // 绑定地址,开始监听
    ChannelFuture f = serverBoot.bind(inetSocketAddress).sync();
    log.info("=========Server is start=========");
    //等待,直到ServerSocket关闭
    f.channel().closeFuture().sync();

从上面可以看出,通道管道线ChannelPipeline是从Socket通道获取,而Socket通道
为ChannelInitializer的参数类型。到ChannelInitializer定义中,并没有发现ChannelPipeline到的相关信息,到ChannelPipeline定义中的java doc 接口定义中有这么一段
Each channel has its own pipeline and it is created automatically when a new channel is created.每个通道拥有自己的管道,当通道创建时,管道自动创建。有这么一句话,我们找channel相关的信息,在上述代码中有个ServerSocket通道NioServerSocketChannel,查看定义:
public class NioServerSocketChannel extends AbstractNioMessageChannel
    implements io.netty.channel.socket.ServerSocketChannel

没有管道相关信息,再往上找
public abstract class AbstractNioMessageChannel extends AbstractNioChannel

仍然没有,再往上找
/**
 * A skeletal {@link Channel} implementation.
 */
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
private final Channel parent;
    private final ChannelId id;
    private final Unsafe unsafe;
    private final DefaultChannelPipeline pipeline;//通道管道线
    private final VoidChannelPromise unsafeVoidPromise = new VoidChannelPromise(this, false);
    private final CloseFuture closeFuture = new CloseFuture(this);

    private volatile SocketAddress localAddress;
    private volatile SocketAddress remoteAddress;
    private volatile EventLoop eventLoop;
    private volatile boolean registered;

    /** Cache for the string representation of this channel */
    private boolean strValActive;
    private String strVal;

    /**
     * Creates a new instance.
     *
     * @param parent
     *        the parent of this channel. {@code null} if there's no parent.
     */
    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
    }
    protected DefaultChannelPipeline newChannelPipeline()
    {
        return new DefaultChannelPipeline(this);
    }
}

到这里终于找到我们想要的了DefaultChannelPipeline
/**
 * The default {@link ChannelPipeline} implementation.  It is usually created
 * by a {@link Channel} implementation when the {@link Channel} is created.
 */
public class DefaultChannelPipeline implements ChannelPipeline {

再看管道接口的定义
public interface ChannelPipeline
   extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Entry<String, ChannelHandler>> 

再看Channel管道线接口定义之前,我们先看一下ChannelInboundInvoker和ChannelOutboundInvoker接口的定义。

public interface ChannelInboundInvoker {

    /**
     * A {@link Channel} was registered to its {@link EventLoop}.
     *通道注册到事件循环
     * This will result in having the  {@link ChannelInboundHandler#channelRegistered(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Inbound通道处理器的channelRegistere方法
     */
    ChannelInboundInvoker fireChannelRegistered();

    /**
     * A {@link Channel} was unregistered from its {@link EventLoop}.
     *通道从事件循环移除
     * This will result in having the  {@link ChannelInboundHandler#channelUnregistered(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Inbound通道处理器的channelUnregistered方法
     */
    ChannelInboundInvoker fireChannelUnregistered();

    /**
     * A {@link Channel} is active now, which means it is connected.
     *通道激活,意味着已经连接诶
     * This will result in having the  {@link ChannelInboundHandler#channelActive(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Inbound通道处理器的channelActive方法
     */
    ChannelInboundInvoker fireChannelActive();

    /**
     * A {@link Channel} is inactive now, which means it is closed.
     *通道以失效,意味通道已经关闭
     * This will result in having the  {@link ChannelInboundHandler#channelInactive(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
    此方法将会触发管道线上的下一个Inbound通道处理器的channelInactive方法
     */
    ChannelInboundInvoker fireChannelInactive();

    /**
     * A {@link Channel} received an {@link Throwable} in one of its inbound operations.
     *通道在inbound的相关操作中,收到一个异常
     * This will result in having the  {@link ChannelInboundHandler#exceptionCaught(ChannelHandlerContext, Throwable)}
     * method  called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Inbound通道处理器的exceptionCaught方法
     */
    ChannelInboundInvoker fireExceptionCaught(Throwable cause);

    /**
     * A {@link Channel} received an user defined event.
     *通道接收一个用户自定义事件
     * This will result in having the  {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)}
     * method  called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
    此方法将会触发管道线上的下一个Inbound通道处理器的userEventTriggeret方法
     */
    ChannelInboundInvoker fireUserEventTriggered(Object event);

    /**
     * A {@link Channel} received a message.
     *通道接收一个消息
     * This will result in having the {@link ChannelInboundHandler#channelRead(ChannelHandlerContext, Object)}
     * method  called of the next {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Inbound通道处理器的channelRead方法
     */
    ChannelInboundInvoker fireChannelRead(Object msg);

    /**
     * Triggers an {@link ChannelInboundHandler#channelReadComplete(ChannelHandlerContext)}
     * event to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     触发管道线上的下一个Inbound通道处理器的channelReadComplete事件
     */
    ChannelInboundInvoker fireChannelReadComplete();

    /**
     * Triggers an {@link ChannelInboundHandler#channelWritabilityChanged(ChannelHandlerContext)}
     * event to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     触发管道线上的下一个Inbound通道处理器的channelReadComplete事件
     */
    ChannelInboundInvoker fireChannelWritabilityChanged();
}


从Inbound通道Invoker的定义来看,ChannelInboundInvoker主要是触发管道线ChannelPipeline上的下一个Inbound通道处理器ChannelInboundHandler的相关方法。ChannelInboundInvoker有点Mina过滤器的意味。



再来看ChannelOutboundInvoker接口定义:

import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.FutureListener;

import java.net.ConnectException;
import java.net.SocketAddress;

public interface ChannelOutboundInvoker {

    /**
     * Request to bind to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation
     * completes, either because the operation was successful or because of an error.
     请求绑定给定socket地址,当操作完成,无论成功或者失败,通知ChannelFuture
     * 
     * This will result in having the
     * {@link ChannelOutboundHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method
     * called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
      此方法将会触发管道线上的下一个Outbound通道处理器的bind方法
     */
    ChannelFuture bind(SocketAddress localAddress);

    /**
     * Request to connect to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation
     * completes, either because the operation was successful or because of an error.
     请求连接给定的socket地址,当操作完成,无论成功或者失败,通知ChannelFuture
     * <p>
     * If the connection fails because of a connection timeout, the {@link ChannelFuture} will get failed with
     * a {@link ConnectTimeoutException}. If it fails because of connection refused a {@link ConnectException}
     * will be used.
     如果连接因为超时失败,ChannelFuture将会获取一个超时异常。如果是拒绝连接,则为连接异常。
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Outbound通道处理器的connect方法
     */
    ChannelFuture connect(SocketAddress remoteAddress);

    /**
     * Request to connect to the given {@link SocketAddress} while bind to the localAddress and notify the
     * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of
     * an error.
     绑定本地socket地址,连接远端socket地址,当操作完成,无论成功或者失败,通知ChannelFuture。
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Outbound通道处理器的connect方法
     */
    ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress);

    /**
     * Request to disconnect from the remote peer and notify the {@link ChannelFuture} once the operation completes,
     * either because the operation was successful or because of an error.
     断开远端的peer连接,当操作完成,无论成功或者失败,通知ChannelFuture。
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#disconnect(ChannelHandlerContext, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Outbound通道处理器的disconnect方法
     */
    ChannelFuture disconnect();
     
    /**
     * Request to close the {@link Channel} and notify the {@link ChannelFuture} once the operation completes,
     * either because the operation was successful or because of
     * an error.
     *请求关闭通道,当操作完成,无论成功或者失败,通知ChannelFuture。
     * After it is closed it is not possible to reuse it again.
     * <p>
     在关闭之后,不能重新使用。
     * This will result in having the
     * {@link ChannelOutboundHandler#close(ChannelHandlerContext, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Outbound通道处理器的close方法
     */
    ChannelFuture close();

    /**
     * Request to deregister from the previous assigned {@link EventExecutor} and notify the
     * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of
     * an error.
     请求从先前分配的EventExecutor中,注销,当操作完成,无论成功或者失败,通知ChannelFuture。
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#deregister(ChannelHandlerContext, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Outbound通道处理器的deregister方法
     *
     */
    ChannelFuture deregister();

    /**
    与上述对应的方法,基本相同,只不过,完成后,给定的ChannelPromise将会被唤醒
     * Request to bind to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation
     * completes, either because the operation was successful or because of an error.
     *
     * The given {@link ChannelPromise} will be notified.
     给定的ChannelPromise将会被唤醒
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#bind(ChannelHandlerContext, SocketAddress, ChannelPromise)} method
     * called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     此方法将会触发管道线上的下一个Outbound通道处理器的bind方法
     */
    ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise);

    /**
    与上述对应的方法,基本相同,只不过,完成后,给定的ChannelPromise将会被唤醒
     * Request to connect to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation
     * completes, either because the operation was successful or because of an error.
     *
     * The given {@link ChannelFuture} will be notified.
     *给定的ChannelPromise将会被唤醒
     * <p>
     * If the connection fails because of a connection timeout, the {@link ChannelFuture} will get failed with
     * a {@link ConnectTimeoutException}. If it fails because of connection refused a {@link ConnectException}
     * will be used.
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise);

    /**
    与上述对应的方法,基本相同,只不过,完成后,给定的ChannelPromise将会被唤醒
     * Request to connect to the given {@link SocketAddress} while bind to the localAddress and notify the
     * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of
     * an error.
     *
     * The given {@link ChannelPromise} will be notified and also returned.
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);

    /**
    与上述对应的方法,基本相同,只不过,完成后,给定的ChannelPromise将会被唤醒
     * Request to disconnect from the remote peer and notify the {@link ChannelFuture} once the operation completes,
     * either because the operation was successful or because of an error.
     *
     * The given {@link ChannelPromise} will be notified.
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#disconnect(ChannelHandlerContext, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelFuture disconnect(ChannelPromise promise);

    /**
    与上述对应的方法,基本相同,只不过,完成后,给定的ChannelPromise将会被唤醒
     * Request to close the {@link Channel} and notify the {@link ChannelFuture} once the operation completes,
     * either because the operation was successful or because of
     * an error.
     *
     * After it is closed it is not possible to reuse it again.
     * The given {@link ChannelPromise} will be notified.
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#close(ChannelHandlerContext, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelFuture close(ChannelPromise promise);

    /**
    与上述对应的方法,基本相同,只不过,完成后,给定的ChannelPromise将会被唤醒
     * Request to deregister from the previous assigned {@link EventExecutor} and notify the
     * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of
     * an error.
     *
     * The given {@link ChannelPromise} will be notified.
     * <p>
     * This will result in having the
     * {@link ChannelOutboundHandler#deregister(ChannelHandlerContext, ChannelPromise)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelFuture deregister(ChannelPromise promise);

    /**
     * Request to Read data from the {@link Channel} into the first inbound buffer, triggers an
     * {@link ChannelInboundHandler#channelRead(ChannelHandlerContext, Object)} event if data was
     * read, and triggers a
     * {@link ChannelInboundHandler#channelReadComplete(ChannelHandlerContext) channelReadComplete} event so the
     * handler can decide to continue reading.  If there's a pending read operation already, this method does nothing.
     * <p>
     请求从第一个inbound buf读取数据,如果有数据读取,则触发Inbound通道处理器的channelRead方法事件和#channelReadComplete
     事件,以便处理器可以决定是否可以继续读取数据。如果一个读操作正在发生,则此方法不做任何事情。
     * This will result in having the
     * {@link ChannelOutboundHandler#read(ChannelHandlerContext)}
     * method called of the next {@link ChannelOutboundHandler} contained in the {@link ChannelPipeline} of the
     * {@link Channel}.
      此方法将会触发管道线上的下一个Outbound通道处理器的read方法
     */
    ChannelOutboundInvoker read();

    /**
     * Request to write a message via this {@link ChannelHandlerContext} through the {@link ChannelPipeline}.
     * This method will not request to actual flush, so be sure to call {@link #flush()}
     * once you want to request to flush all pending data to the actual transport.
     请求通过通道处理器上下文发送消息到Channel管道线。此方不会请求实际的刷新,如果你想请求刷新待发送的数据
     到transport,必须调用flush方法。
     */
    ChannelFuture write(Object msg);

    /**
    与上述对应的方法,基本相同,只不过,完成后,给定的ChannelPromise将会被唤醒
     * Request to write a message via this {@link ChannelHandlerContext} through the {@link ChannelPipeline}.
     * This method will not request to actual flush, so be sure to call {@link #flush()}
     * once you want to request to flush all pending data to the actual transport.
     */
    ChannelFuture write(Object msg, ChannelPromise promise);

    /**
     * Request to flush all pending messages via this ChannelOutboundInvoker.
     通过Outbound通道Invoker,刷新待发送的消息到transport
     */
    ChannelOutboundInvoker flush();

    /**
     * Shortcut for call {@link #write(Object, ChannelPromise)} and {@link #flush()}.
     此方法为#write(Object, ChannelPromise)和#flush的快捷方式
     */
    ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);

    /**
     * Shortcut for call {@link #write(Object)} and {@link #flush()}.
     此方法为#write(Object)和#flush的快捷方式
     */
    ChannelFuture writeAndFlush(Object msg);

    /**
     * Return a new {@link ChannelPromise}.
     创建一个ChannelPromise
     */
    ChannelPromise newPromise();

    /**
     * Return an new {@link ChannelProgressivePromise}
     创建一个ChannelProgressivePromise
     */
    ChannelProgressivePromise newProgressivePromise();

    /**
     * Create a new {@link ChannelFuture} which is marked as succeeded already. So {@link ChannelFuture#isSuccess()}
     * will return {@code true}. All {@link FutureListener} added to it will be notified directly. Also
     * every call of blocking methods will just return without blocking.
     创建一个已经标记成功的通道结果。ChannelFuture#isSuccess方法返回ture。所有添加到通道结果的监听器,将会被直接唤醒。
     每个阻塞的方法,将会无阻塞返回。
     */
    ChannelFuture newSucceededFuture();

    /**
     * Create a new {@link ChannelFuture} which is marked as failed already. So {@link ChannelFuture#isSuccess()}
     * will return {@code false}. All {@link FutureListener} added to it will be notified directly. Also
     * every call of blocking methods will just return without blocking.
     创建一个已经标记失败的通道结果。ChannelFuture#isSuccess方法返回false。所有添加到通道结果的监听器,将会被直接唤醒。
     每个阻塞的方法,将会无阻塞返回。
     */
    ChannelFuture newFailedFuture(Throwable cause);

    /**
     * Return a special ChannelPromise which can be reused for different operations.
     返回一个特别的ChannelPromise,可以重用于不同的操作。
     * <p>
     * It's only supported to use
     * it for {@link ChannelOutboundInvoker#write(Object, ChannelPromise)}.
     仅仅支持ChannelOutboundInvoker#write(Object, ChannelPromise)方法
     * 

     * 
     * Be aware that the returned {@link ChannelPromise} will not support most operations and should only be used
     * if you want to save an object allocation for every write operation. You will not be able to detect if the
     * operation  was complete, only if it failed as the implementation will call
     * {@link ChannelPipeline#fireExceptionCaught(Throwable)} in this case.
     注意,返回的ChannelPromise,不支持大部分的操作,如果在为每个写操作保存一个分配的对象时,应该使用此方法。
     如果操作已经完成,当且仅当,由于调用ChannelPipeline#fireExceptionCaught引起的失败,你不能够探测时,可以使用
     此方法创建的ChannelPromise
     * 

     * [b]Be aware this is an expert feature and should be used with care![/b]
     请谨慎使用。
     */
    ChannelPromise voidPromise();
}

Outbound通道Invoker ChannelOutboundInvoker主要是触发触发管道线ChannelPipeline上的下一个Outbound通道处理器ChannelOnboundHandler的相关方法,同时增加了一下通道结果创建方法,ChannelOutboundInvoker也有点Mina过滤器的意味,只不过不像ChannelInboundInvoker的方法命名那么相似。在Outbound通道Invoker的方法定义中,我们看到有很多类型的返回结果,比如:ChannelFuture,ChannelPromise,ChannelProgressivePromise这个我们放在下一篇来看。


总结:
每个通道Channel拥有自己的管道Pipeline,当通道创建时,管道自动创建,默认为DefaultChannelPipeline。Inbound通道Invoker ChannelInboundInvoker主要是触发管道线ChannelPipeline上的下一个Inbound通道处理器ChannelInboundHandler的相关方法。ChannelInboundInvoker有点Mina过滤器的意味。Outbound通道Invoker ChannelOutboundInvoker主要是触发触发管道线ChannelPipeline上的下一个Outbound通道处理器ChannelOnboundHandler的相关方法,同时增加了一下通道结果创建方法,
ChannelOutboundInvoker也有点Mina过滤器的意味,只不过不像ChannelInboundInvoker的方法命名那么相似。

文章评论

程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
如何成为一名黑客
如何成为一名黑客
鲜为人知的编程真相
鲜为人知的编程真相
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
我是如何打败拖延症的
我是如何打败拖延症的
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
老程序员的下场
老程序员的下场
Java程序员必看电影
Java程序员必看电影
旅行,写作,编程
旅行,写作,编程
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
代码女神横空出世
代码女神横空出世
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
一个程序员的时间管理
一个程序员的时间管理
编程语言是女人
编程语言是女人
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
中美印日四国程序员比较
中美印日四国程序员比较
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
 程序员的样子
程序员的样子
程序员必看的十大电影
程序员必看的十大电影
那些争议最大的编程观点
那些争议最大的编程观点
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
每天工作4小时的程序员
每天工作4小时的程序员
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
程序员应该关注的一些事儿
程序员应该关注的一些事儿
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
漫画:程序员的工作
漫画:程序员的工作
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
程序员的鄙视链
程序员的鄙视链
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
总结2014中国互联网十大段子
总结2014中国互联网十大段子
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
程序员都该阅读的书
程序员都该阅读的书
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
我的丈夫是个程序员
我的丈夫是个程序员
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
程序员和编码员之间的区别
程序员和编码员之间的区别
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有