Netty4的代码比我想象的要复杂的多,不过Netty4很好的将这种复杂性隐藏了起来,暴露出来的,是一个相对容易使用的接口。Bootstrap就是Netty试图隐藏这种复杂性的一个例子。
bootstrap包
bootstrap包是Netty4代码里最简单的一个包,总共只有4个类:
Bootstrap继承结构
AbstractBootstrap是抽象类,有两个具体的实现,Bootstrap和ServerBootstrap:
Bootstrap例子
Netty4自带的例子里有一个EchoClient,看看它是如何使用Bootstrap启动一个客户端程序的:
-
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入手:
-
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,例如下面这些:
-
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,如下:
-
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实现:
-
public B channel(Class<? extends C> channelClass) {
-
if (channelClass == null) {
-
throw new NullPointerException("channelClass");
-
}
-
return channelFactory(new BootstrapChannelFactory<C>(channelClass));
-
}
默认的ChannelFactory实现使用反射创建Channel实例:
-
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()方法:
-
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
-
if (remoteAddress == null) {
-
throw new NullPointerException("remoteAddress");
-
}
-
validate();
-
return doConnect(remoteAddress, localAddress);
-
}
connect()方法调用validate()方法看各个Part是否准备就绪,然后调用doConnect()方法:
-
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()
-
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的构造函数可以看出:
-
protected AbstractChannel(Channel parent) {
-
this.parent = parent;
-
unsafe = newUnsafe();
-
pipeline = new DefaultChannelPipeline(this);
-
}
Bootstrap.init()方法
-
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就接通服务器,可以收发消息了!