您的位置:首页 > Web前端 > BootStrap

Netty4学习笔记(2)-- Bootstrap

2015-12-30 10:55 696 查看
转自:http://blog.csdn.net/zxhoo/article/details/17419229

Netty4的代码比我想象的要复杂的多,不过Netty4很好的将这种复杂性隐藏了起来,暴露出来的,是一个相对容易使用的接口。Bootstrap就是Netty试图隐藏这种复杂性的一个例子。

bootstrap包

bootstrap包是Netty4代码里最简单的一个包,总共只有4个类:




Bootstrap继承结构

AbstractBootstrap是抽象类,有两个具体的实现,Bootstrap和ServerBootstrap:



Bootstrap例子

Netty4自带的例子里有一个EchoClient,看看它是如何使用Bootstrap启动一个客户端程序的:

[java] view
plaincopy





public class EchoClient {  

  

    private final String host;  

    private final int port;  

    private final int firstMessageSize;  

  

    public EchoClient(String host, int port, int firstMessageSize) {  

        this.host = host;  

        this.port = port;  

        this.firstMessageSize = firstMessageSize;  

    }  

  

    public void run() throws Exception {  

        // Configure the client.  

        EventLoopGroup group = new NioEventLoopGroup();  

        try {  

            Bootstrap b = new Bootstrap();  

            b.group(group)  

             .channel(NioSocketChannel.class)  

             .option(ChannelOption.TCP_NODELAY, true)  

             .handler(new ChannelInitializer<SocketChannel>() {  

                 @Override  

                 public void initChannel(SocketChannel ch) throws Exception {  

                     ch.pipeline().addLast(  

                             //new LoggingHandler(LogLevel.INFO),  

                             new EchoClientHandler(firstMessageSize));  

                 }  

             });  

  

            // Start the client.  

            ChannelFuture f = b.connect(host, port).sync();  

  

            // Wait until the connection is closed.  

            f.channel().closeFuture().sync();  

        } finally {  

            // Shut down the event loop to terminate all threads.  

            group.shutdownGracefully();  

        }  

    }  

  

    public static void main(String[] args) throws Exception {  

    // ...  

    }  

}  

Builder模式?

看上面的例子,Bootstrap的使用很像Builder模式,Bootstrap就是Builder,EventLoopGroup、Channel和Handler等是各种Part。稍有不同的是,准备好各种Part后,并不是直接build出一个Product来,而是直接通过connect()方法使用这个Product。

AbstractBootstrap

为了弄清楚Bootstrap如何工作,我们先从AbstractBootstrap入手:

[java] view
plaincopy





public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {  

  

    private volatile EventLoopGroup group;  

    private volatile ChannelFactory<? extends C> channelFactory;  

    private volatile SocketAddress localAddress;  

    private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();  

    private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();  

    private volatile ChannelHandler handler;  

    // ...  

}  

可以看到,AbstractBootstrap这个抽象Builder一共需要有6个Part,如下图所示:



设置各个Part

AbstractBootstrap有一组方法用来设置各个Part,例如下面这些:

[java] view
plaincopy





public B group(EventLoopGroup group)  

public B channel(Class<? extends C> channelClass)  

public B channelFactory(ChannelFactory<? extends C> channelFactory)  

public B localAddress(SocketAddress localAddress)  

public <T> B option(ChannelOption<T> option, T value)  

public <T> B attr(AttributeKey<T> key, T value)  

public B handler(ChannelHandler handler)  

还有一组对应方法获得各个Part,如下:

[java] view
plaincopy





final SocketAddress localAddress()  

final ChannelFactory<? extends C> channelFactory()  

final ChannelHandler handler()  

public final EventLoopGroup group()  

final Map<ChannelOption<?>, Object> options()  

final Map<AttributeKey<?>, Object> attrs()  

ChannelFactory

AbstractBootstrap通过ChannelFactory创建Channel实例,channel(channelClass)方法看起来好像是设置了一个Channel,但实际上只是设置了默认的ChannelFactory实现:

[java] view
plaincopy





public B channel(Class<? extends C> channelClass) {  

    if (channelClass == null) {  

        throw new NullPointerException("channelClass");  

    }  

    return channelFactory(new BootstrapChannelFactory<C>(channelClass));  

}  

默认的ChannelFactory实现使用反射创建Channel实例:

[java] view
plaincopy





private static final class BootstrapChannelFactory<T extends Channel> implements ChannelFactory<T> {  

    private final Class<? extends T> clazz;  

  

    BootstrapChannelFactory(Class<? extends T> clazz) {  

        this.clazz = clazz;  

    }  

  

    @Override  

    public T newChannel() {  

        try {  

            return clazz.newInstance();  

        } catch (Throwable t) {  

            throw new ChannelException("Unable to create Channel from class " + clazz, t);  

        }  

    }  

}  

Bootstrap.connect()

再来看Bootstrap类的connect()方法:

[java] view
plaincopy





public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {  

    if (remoteAddress == null) {  

        throw new NullPointerException("remoteAddress");  

    }  

    validate();  

    return doConnect(remoteAddress, localAddress);  

}  

connect()方法调用validate()方法看各个Part是否准备就绪,然后调用doConnect()方法:

[java] view
plaincopy





private ChannelFuture doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {  

    final ChannelFuture regFuture = initAndRegister();  

    final Channel channel = regFuture.channel();  

    if (regFuture.cause() != null) {  

        return regFuture;  

    }  

  

    final ChannelPromise promise = channel.newPromise();  

    if (regFuture.isDone()) {  

        doConnect0(regFuture, channel, remoteAddress, localAddress, promise);  

    } else {  

        regFuture.addListener(new ChannelFutureListener() {  

            @Override  

            public void operationComplete(ChannelFuture future) throws Exception {  

                doConnect0(regFuture, channel, remoteAddress, localAddress, promise);  

            }  

        });  

    }  

  

    return promise;  

}  

doConnect()方法首先调用了initAndRegister()方法,然后又调用了doConnect0()方法,方法调用示意图如下:



AbstractBootstrap.initAndRegister()

[java] view
plaincopy





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);  

    // ...  

}  

initAndRegister()方法用ChannelFactory创建了一个Channel的实例,然后调用init()方法初始化Channel,最后将Channel注册到EventLoopGroup上:



而Channel在实例化的时候已经自动关联了Pipeline,这点从AbstractChannel的构造函数可以看出:

[java] view
plaincopy





protected AbstractChannel(Channel parent) {  

    this.parent = parent;  

    unsafe = newUnsafe();  

    pipeline = new DefaultChannelPipeline(this);  

}  

 


Bootstrap.init()方法

[java] view
plaincopy





void init(Channel channel) throws Exception {  

    ChannelPipeline p = channel.pipeline();  

    p.addLast(handler());  

    // ...  

}  

Bootstrap.init()方法把Handler添加到了Pipeline的末尾,到这里,Channel就准备就绪了:





继续Bootstrap.doConnect()

initAndRegister()方法结束之后,doConnect()方法紧接着调用了doConnect0()方法,doConnect0()方法继而调用了Channel.connect()方法,这样Channel就接通服务器,可以收发消息了!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  netty