BootStrap ServerBootStarp
BootStarp 意思是引导,一个Netty 应用通常由一个BootStarp 开始,主要作用是配置整个Netty程序,串联各个组件,Netty中BootStarp 类是客户端程序的启动引导类,ServerBootStarp 是服务端启动引导类。
常见方法
- public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup),该方法用于Netty服务端,用来设置两个NioEventLoopGroup
- public B group(EventLoopGroup group) 该方法用于客户端,用来设置一个NioEventLoopGroup
- public B channel(Class<? extends C> channelClass) 该方法用来设置一个服务器端的通道实现 默认NioServerSocketChannel
- public B option(ChannelOption option, T value) 用来给 ServerChannel 添加配置
- public ServerBootstrap childOption(ChannelOption childOption, T value),用来给接收到的通道添加配置
- public ServerBootstrap childHandler(ChannelHandler childHandler),该方法用来设置业务处理类(自定义的Handler)
- public ChannelFuture bind(int inetPort) ,该方法用于服务器端,用来设置占用的端口号
- public ChannelFuture connect(String inetHost, int inetPort) ,该方法用于客户端,用来连接服务器端
一般在启动一个服务器端的ServerBootStarp时,我们需要指定这几个参数
public static void main(String[] args) throws InterruptedException {
// BossGroup --- Channel --> WorkerGroup
// BossGroup 只处理客户端的连接事件
EventLoopGroup bossGroup = new NioEventLoopGroup();
// WorkerGroup -> NioEventLoopGroup -> NioEventLoop -> Pipeline
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
// NioServerSocketChannel 这个是BossGroup 和 WorkerGroup之间的通道
.channel(NioServerSocketChannel.class)
// SocketChannel 这个是客户端和服务器端之间的通道 以及添加对这个通道产生数据的handler
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 添加我们自定义的Handler
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("服务器 ok");
// 服务器端绑定监测的端口 并启动Netty服务器端
ChannelFuture channelFuture = bootstrap.bind(6668).sync();
channelFuture.channel().closeFuture().sync();
} finally {
// 优雅的关闭两个线程池
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
bootstrap.group(bossGroup, workerGroup)
ServerBootStarp 类定义的几个常量 都添加了volatile 关键字 保证了线程之间的可见性
private volatile EventLoopGroup childGroup;
private volatile ChannelHandler childHandler;
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
/**
调用父类AbstractBootstrap构造 指定BossGroup
*/
super.group(parentGroup);
ObjectUtil.checkNotNull(childGroup, "childGroup");
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
// 指定WorkerGroup
this.childGroup = childGroup;
return this;
}
bootstrap.channel(NioServerSocketChannel.class)
// ChannelFactory通过反射的方式创建BossGroup 与 WorkerGroup 之间的通道。在这里我们指定反射创建的通道类型
public B channel(Class<? extends C> channelClass) {
return channelFactory(new ReflectiveChannelFactory<C>(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}
// 反射Channel工厂
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
// 得到要创建通道的构造方法
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
@Deprecated
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
ObjectUtil.checkNotNull(channelFactory, "channelFactory");
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
// 指定了工厂对象
this.channelFactory = channelFactory;
return self();
}
bootstrap.bind(6668).sync()
这个方法在ServerBootStarp 的父类 AbstractBootstarp
启动Netty服务器端并且绑定要监听的端口号
public ChannelFuture bind(InetAddress inetHost, int inetPort) {
return bind(new InetSocketAddress(inetHost, inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
/**
// 判断BossGroup 是否为空
public B validate() {
if (group == null) {
throw new IllegalStateException("group not set");
}
// 判断创建channel的工厂为空
if (channelFactory == null) {
throw new IllegalStateException("channel or channelFactory not set");
}
return self();
}
*/
validate();
// 最终会调用这个方法启动Netty服务器端
return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
doBind(final SocketAddress localAddress)
private ChannelFuture doBind(final SocketAddress localAddress) {
// 初始化 NIOServerSocketChannel
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
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) {
// Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
// IllegalStateException once we try to access the EventLoop of the Channel.
promise.setFailure(cause);
} else {
// Registration was successful, so set the correct executor to use.
// See https://github.com/netty/netty/issues/2586
promise.registered();
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
initAndRegister()
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// 通过ReflectiveChannelFactory 我们前面指定要创建的NIOServerSocketChannel类型的通道
channel = channelFactory.newChannel();
跟踪源码发现 该方法创建了NIOServerSocketChannel AbstractChannel 以及 AbstractNioChannel
NIOServerSocketChannel
1、初始化了 SelectorProvider 多路复用I/O 的系统实现
2、初始化NioServerSocketChannelConfig 用于对外展示一些配置
AbstractChannel
1、创建默认的ChannelId
2、创建了一个NioMessageUnsafe 用来操作消息
3、创建了DefaultChannelPipeline 管道 用于管理handler
AbstractNioChannel
1、指定SelectableChannel 的实现类 ServerSocketChannelImpl
2、设置为非阻塞模型
init(channel);
init方法这是个抽象方法(AbstractServerBootstarp类定义的) 但是是有ServerBootStarp实现的
将这个方法在下面单独拿出来说
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
init(Channel channel)
void init(Channel channel) {
// 设置NIOServerSocketChannel 的tcp属性
setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));
// 将在AbstractBootstarp初始化的DefaultChannelPipeline
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions =
childOptions.entrySet().toArray(newOptionArray(0));
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
// 将channel和pipeline进行关联
1、初始化了DefaultChannelContext 将handler进行了封装
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
class DefaultChannelPipeline.addLast()
/**
因为是一个双向链表 所以做了同步处理
*/
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
// 将我们自定义的handler 封装为DefaultChannelContext
newCtx = newContext(group, filterName(name, handler), handler);
// 添加到队列中去 这里 addLast/addFirst 都是添加到tail的前面或者head的后面 因为在初始化DefaultChannelContext 的时候初始化了这两个常量 为了是处理进站和出站的消息。
这里很清楚的看到我们添加的handler的都是添加到了tail的前面
/**
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
*/
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventLoop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
- addLast()方法在DefaultChannelPipeline类中
- 首先检查这个handler是否符合标准
- 创建一个DefaultChannelHandllerContext 对象封装handler。这个DefaultChannelHandllerContext 对象是channel 和 pipeline 之间的关联。这个对象包含了handler 和 pipeline 而通过pipeline又可以找到相对应的channel。
- 最后将DefaultChannelHandlerContext加入到双向链表中
- 最后,同步或异步或者晚点调用callHandlerAdded()方法