Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完成 Netty 的客户端或服务器端的 Netty 初始化.利用BootStrap我们可以实现创建channel,把channel注册在EventLoop上,发起连接等功能.
BootStrap的类结构如下:
1. Client端启动实例
下面是个简单的客户端实例,我们用这个来分析BootStrap的整个流程.
public class Client {
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public static void main(String[] args) 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() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new MyProtocolEncoder());
ch.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture future = b.connect(HOST, PORT).sync();
future.channel().writeAndFlush("Hello Netty Server ,I am a common client");
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
2. group()
public B group(EventLoopGroup group) {
if (group == null) {
throw new NullPointerException("group");
}
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group; //设置成员变量group 为传入的group
return self();
}
- 这里设置
EventLoopGroup
,是为了以后注册和handle事件做准备,EventLoopGroup
可以理解成一个线程池.在后面注册和handler事件的时候,会从EventLoopGroup
取线程处理.
3. channel()
public B channel(Class extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new ReflectiveChannelFactory(channelClass));
}
- 这里并不是返回channel,而是返回一个channelFactory,利用工厂方法构造channel.而下面这个则是一个channelFactory,他是根据传入的Class,通过反射构造channel.
public class ReflectiveChannelFactory implements ChannelFactory {
private final Class extends T> clazz;
public ReflectiveChannelFactory(Class extends T> clazz) {
if (clazz == null) {
throw new NullPointerException("clazz");
}
this.clazz = clazz;
}
//通过返回获取channel实例
@Override
public T newChannel() {
try {
return clazz.getConstructor().newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
}
4. option()
public B option(ChannelOption option, T value) {
if (option == null) {
throw new NullPointerException("option");
}
if (value == null) { //value为null,则表示删除这个option
synchronized (options) {
options.remove(option);
}
} else {
synchronized (options) {
options.put(option, value);
}
}
return self();
}
- 为Channel设置一些可选的性质.当value为null的时候表示删除这个option.
5. handler()
public B handler(ChannelHandler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
return self();
}
- 设置handler,这里handler是用户自定义处理连接逻辑.例如编码器或者自定义的handler.通常来说我们通过
ChannelInitializer
的init
来添加handler.
6. connect()
public ChannelFuture connect(String inetHost, int inetPort) {
return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
}
public ChannelFuture connect(SocketAddress remoteAddress) {
if (remoteAddress == null) {
throw new NullPointerException("remoteAddress");
}
//检验各个part是否准备好
validate();
return doResolveAndConnect(remoteAddress, config.localAddress());
}
- 先验证各个part是否准备好,然后再发起连接.
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister(); //1
final Channel channel = regFuture.channel(); //获取channel
if (regFuture.isDone()) { //异步的结果返回
if (!regFuture.isSuccess()) { //不成功
return regFuture;
}
return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
} else {
//异步结果还没出来,添加监听器来监听
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause(); //异步结果
if (cause != null) {
//注册失败
promise.setFailure(cause);
} else {
// 注册成功了.
promise.registered();
// 发起连接
doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
}
}
});
return promise;
}
}
- 上面是整个注册,连接的逻辑.下面这部分单独把注册部分拿出来.
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel(); //创建实例
init(channel);
} catch (Throwable t) {
if (channel != null) {
channel.unsafe().closeForcibly();
//如果到这里还没注册channel,则强制使用GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
//如果到这里还没注册channel,则强制使用GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
//在这里异步注册Channel
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close(); //已经注册成功了
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
- 上面是整个注册的逻辑,采用是异步的策略,也就是说我们可以在程序中,根据监听器的结果来判断注册是否成功.
void init(Channel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(config.handler());
final Map, Object> options = options0();
synchronized (options) {
setChannelOptions(channel, options, logger);
}
final Map, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry, Object> e: attrs.entrySet()) {
channel.attr((AttributeKey
- 在这里初始化channel.并向
channelPipeline
中添加handler.为channel设置option和Attribute
private ChannelFuture doResolveAndConnect0(final Channel channel, SocketAddress remoteAddress,
final SocketAddress localAddress, final ChannelPromise promise) {
try {
//获取到该channel绑定的EventLoop
final EventLoop eventLoop = channel.eventLoop();
final AddressResolver resolver = this.resolver.getResolver(eventLoop);
if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) {
//已经解析了,或者没有办法解析.
doConnect(remoteAddress, localAddress, promise);
return promise;
}
final Future resolveFuture = resolver.resolve(remoteAddress);
if (resolveFuture.isDone()) { //返回异步解析的结果
final Throwable resolveFailureCause = resolveFuture.cause();
if (resolveFailureCause != null) {
// 不能立即解析
channel.close();
promise.setFailure(resolveFailureCause);
} else {
// 成功解析,则连接
doConnect(resolveFuture.getNow(), localAddress, promise);
}
return promise;
}
// 没有立刻解析,则添加监听器等待解析的结果
resolveFuture.addListener(new FutureListener() {
@Override
public void operationComplete(Future future) throws Exception {
if (future.cause() != null) {
//解析失败
channel.close();
promise.setFailure(future.cause());
} else {
// 解析成功,发起连接.
doConnect(future.getNow(), localAddress, promise);
}
}
});
} catch (Throwable cause) {
promise.tryFailure(cause);
}
return promise;
}
- 以上是异步解析地址.
private static void doConnect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
final Channel channel = connectPromise.channel();
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
//本地地址
if (localAddress == null) {
channel.connect(remoteAddress, connectPromise);
} else {
channel.connect(remoteAddress, localAddress, connectPromise);
}
connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
});
}
- 上面这部分是真正的异步连接服务器.
7. 总结
通过上面的叙述,我们不难看出来,BootStrap所做的3件事.无非在这过程中,多次利用异步来获取结果.
- 创建channel,并初始化
- 注册channel
- 连接到服务器