ServerBootstrap 服务启动类
结构: 继承 AbstractBootstrap
抽象类
使用案例:
ServerBootstrap server = new ServerBootstrap();
server.group(new NioEventLoopGroup(), new NioEventLoopGroup()); // EventLoopGroup接口
server.channel(NioServerSocketChannel.class); // Channel.class类类型
server.childHandler(new ChannelInitializer<Channel>(){ // ChannelHandler接口
initChannel(Channel c){
c.pipeline().addLast(new SimpleChannelInboundHandler<Object>(){ // ChannelHandler接口
channelRead0(ChannelHandlerContext ctx, Object msg) // 发送消息
});
}
});
ChannelFutrue future = server.bind(8899).sync();
方法:group(EventLoopGroup) 配置线程池
group(EventLoopGroup, EventLoopGroup)
创建 NioEventLoopGroup 线程组(池). 为 ServerBootstrap
配置 childGroup 线程池, AbstractBootstrap
父类配置 group 线程池.
(这里暂时未讲解,一个线程池与二个线程池的区别)
方法:channel(Channel.class) 配置传输管道
注意, NioServerSocketChannel
是 NIO 的传输管道. 内部是封装 java.nio.channels.ServerSocketChannel
管道. 通过nio管道实现消息传输。
这里源码追踪: AbstractBootstrap 类中 channel 方法
public B channel(Class<? extends C> channelClass) {
return channelFactory(new ReflectiveChannelFactory<C>(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}
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();
}
通过 NioServerSocketChannel
创建 ReflectiveChannelFactory
管道工厂, 这里简单介绍 ReflectiveChannelFactory
实现, 通过 NioServerSocketChannel
根据class类型获取构造器并创建对象.
方法:childHandler(ChannelHandler) 配置管道处理器
自定义实现 ChannelHandler
实现, 这里配置的是 ChannelInitializer
并实现 initChannel
抽象方法. 可通过管道获取 ChannelPipeline
对象获取到上下文实现消息传输
这个暂时不解析, 先按主流程思路走…
方法:bind(端口) 绑定端口
根据端口创建 InetSocketAddress
对象. 其中 doBind(SocketAddress)
方法为核心.
doBind 源码解析:
private ChannelFuture doBind(final SocketAddress localAddress) {
// 初始化管道 和 线程池注册管道
final ChannelFuture regFuture = initAndRegister(); // #see NioEventLoopGroup.register()
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
if (regFuture.isDone()) { // 如果此任务完成,则返回{@code true}
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} 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) {
// EventLoop上的注册失败了,所以当我们试图访问通道的EventLoop时,不能让ChannelPromise直接导致IllegalStateException
promise.setFailure(cause);
} else {
// 注册成功,因此请设置要使用的正确执行程序
promise.registered();
doBind0(regFuture, channel, localAddress, promise); // do
}
}
});
return promise;
}
}
该doBind()方法第一步,是通过
initAndegister()
方法管道初始化和注册管道获取ChannelFuture
管道响应.
第二步, 通过注册管道得到ChannelFuture
对象为该注册监听器
初始化管道, 使用管道工厂也就是上面所说的
ReflectiveChannelFactory
对象通过它创建NioServerSocketChannel
管道。
在 AbstractBootstrap
中提供了一个抽象方法 init(Channel)
给子类去初始化管道. ServerBootstrap
对象为 NIO 服务端,也就是 AbstractBootstrap
抽象类的实现类.
接下来看服务端如何初始化管道的…
void init(Channel channel) {
// 设置管道选项
setChannelOptions(channel, options0().entrySet().toArray(EMPTY_OPTION_ARRAY), logger);
// 设置管道的一些属性
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
ChannelPipeline p = channel.pipeline(); // DefaultChannelPipeline
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions = childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY);
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));
}
});
}
});
}
服务端在初始化管道先设置了管道选项 setChannelOptions
方法, 设置了管道属性 setAttributes
方法. 在这里二个方法不作深一步解析,有兴趣可以去理解.
channel.pipeline() 方法是获取, 创建的默认的 ChannelPipeline
接口的实现类 DefaultChannelPipeline
。
ChannelPipeline
理解
ChannelPipeline 类是 ChannelHandler 实例对象的链表,用于处理或截获通道的接收和发送数据。它提供了一种高级的截取过滤模式(类似serverlet中的filter功能),让用户可以在 ChannelPipeline 中完全控制一个事件以及如何处理ChannelHandler与ChannelPipeline的交互。
先跳过 ChannelPipeline
处理 ChannelHandler
逻辑。 我们通过管道获取到 DefaultChannelPipeline
对象. 在这里内部帮我们添加一个 ChannelHandler
管道处理器. ServerBootstrapAcceptor
对象. 并是由单独的线程的运行。
ChannelHanlder 管道处理器, 是由单独的线程来处理的
通过上述理解得知。在 netty 中我们先通过 Channel 获取 管道处理器的管理者
。 也是就 ChannelPipeline
对象。通过它添加 ChannelHandlelr
管道处理器. 用它实现我们的消息传输.
看完 ServerBootstrap 重写 init() 方法,咋们回过头再来看 AbstractBootstap 中的 initAndRegister() 方法逻辑. 把管道注册到 NioEventLoopGroup
对象上。下面先看看 NioEventLoopGroup 的初始化流程…
最后看 ChannelPipeline
处理 ChannelHandler
的呢…
NioEventLoopGroup 初始化流程
在看 NioEventLoopGroup
注册管道前, 我们先来看下它的类结构.
一级 NioEventLoopGroup =>
二级 MultithreadEventLoopGroup => 实现 EventLoopGroup 接口
三级 MultithreadEventExecutorGroup =>
四级 AbstractEventExecutorGroup => 实现 EventExecutorGroup 接口
除了 NioEventLoopGroup
其它都是抽象类. 我们来看下 一级 NioEventLoopGroup 的初始化流程吧
public NioEventLoopGroup() {
this(0); //默认线程数为0
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null); //默认执行器为null
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());//
}
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);//
}
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
// newChild 方法为三级类中的抽象方法
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
EventLoopTaskQueueFactory queueFactory = args.length == 4 (EventLoopTaskQueueFactory) args[3] : null;
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2], queueFactory);
}
在一级类构造器中使用到以下三个对象: NioEventLoopGroup 类中的
newChild()
方法中创建NioEventLoop
时需要
SelectorProvider.provider() :: 选择器提供者
DefaultSelectStrategyFactory.INSTANCE :: 选择器策略模式工厂
RejectedExecutionHandlers.reject() :: 可以理解为异常处理器
二级 MultithreadEventLoopGroup 初始化
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
在二级构造器里面发现如果不设置线程数,就会有个默认的线程数变量 DEFAULT_EVENT_LOOP_THREADS
默认线程数是取的虚拟机可用的处理器数量的二倍 * 2 。 这里可以通过设置 netty 的属性设置 io.netty.eventLoopThreads
线程数。
三级 MultithreadEventExecutorGroup 初始化
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i++) {
boolean success = false;
try {
children[i] = newChild(executor, args); // create
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
// PowerOfTwoEventExecutorChooser
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e : children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
注意: 三级类中的构造器初始化。其中有个 EventExecutor []
事件执行器数组, 与 EventExecutorChooserFactory
事件执行器选择器工厂对象
步骤:
- 如果
Executor
参数为空则创建ThreadPerTaskExecutor
对象。(这里executor 默认为空) - 创建长度为
虚拟机可用的处理器数量 * 2
的执行器数组。 - 为创建的执行器数组中的每个
EventExecutor
创建赋值, 这里看一级类 NioEventLoopGroup 的 newChild() 重写方法。 - 创建
EventExecutorChooserFactory
工厂, 根据执行器数组长度来判断创建对象。这里创建为PowerOfTwoEventExecutorChooser
该对象主要用来选取数组中的 EventExecutor 。 - 创建
FutureListener
监听器, 为每个 EventExecutor 添加这个监听器。 - 复制
事件执行器
到新的集合,readonlyChildren
属性为已经读取的事件执行器。
DefaultEventExecutorChooserFactory 工厂 创建事件执行选择器
逻辑。 如果为长度是为2的n次幂的则创建PowerOfTwoEventExecutorChooser
对象, 否则创建GenericEventExecutorChooser
对象。
Power 取 EventExecutor 的逻辑为下图
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
选取 EventExecutor数组中的逻辑…
NioEventLoopGroup 注册管道流程
在 AbstractBootstrap
中的 initAndRegister()
方法中通过拿到一级类 NioEventLoopGroup
对象然后把 Channel
注册到当中。
具体注册实现步骤:
- 在二级类
MultithreadEventLoopGroup
中register()
方法处理逻辑。- 在三级类
MultithreadEventExecutorGroup
通过EventExecutorChooser
事件执行选择器,获取选择的EventExecutor
(选取规则上图标记部份) - 通过
EventExecutor
的实现类NioEventLoop
对象注册管道 Channel 。
- 在三级类
上述中发现, NioEventLoopGroup 注册管道,交给了 NioEventLoop. 而 NioEventLoopGroup 就是只做了一个 创建 NioEventLoop 和 选择器选取 NioEventLoop 操作。
NioEventLoop 初始化流程
先来看 NioEventLoop 初始化流程. 在创建 NioEventLoop 时有几个重要的参数。我们来回顾一下。
参数一:
NioEventLoopGroup
也就是创建的对象, 该包含所有的EventExecutor
参数二:Executor
执行器 , 在NioEventLoopGroup的三级类 MultithreadEventExecutorGroup 中初始化
默认创建的是,ThreadPerTaskExecutor
对象。
参数三:SelectorProvider
选择器提供者, 这个jdk 用来创建Selector
的。
参数四:SelectStrategy
选择器策略
参数五:RejectedExecutionHandler
拒绝执行处理器,可以理解为异常处理器
里面几个重要属性:
java.nio.channels.Selector
java.nio.channels.spi.SelectorProvider
io.netty.util.concurrent.EventExecutorGroup
java.util.concurrent.Executor
java.util.Queue
回到 NioEventLoop
注册逻辑上, 下面代码发现.
// 二级类 SingleThreadEventLoop 中的 register() 方法逻辑
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
- 创建了
DefaultChannelPromise
对象。 - 拿到
Channel
中的Unsafe
对象. 为二级类AbstractNioMessageChannel
中的内部类一级NioMessageUnsafe
对象。 - 注册逻辑在内部类
三级类 NioMessageUnsafe
中, 注册管道逻辑看下源码。- 先判断是否注册,如已注册直接返回错误信息
- 判断
eventLoop
是否为NioEventLoop
NioEventLoop
赋值到当前Channel
上。 也就是说 EventLoop 对应一个 Channel。isEventLoop()
判断当前线程与 NioEventLoop 中的 thread 线程是否相等. 这里创建 NioEventLoop 中的线程属性是null, 所以不相等。 false- 这里为
EventLoop
创建一个新的线程并执行调用register0(ChannelPromise)
方法。
- 注册
register0(ChannelPromise)
方法逻辑。- 检查通道是否仍然打开,因为当寄存器调用在 eventLoopFuture 之外时,通道可能会关闭,从而无法取消。
doRegister()
逻辑, 在 Channel 的三级类中AbstractNioChannel
重写,- 拿到
ServerSocketChannel
服务端, 注册Selector
, 和 ops 为 0, 和属性 当前NioServerSocketChannel
对象。 - 返回拿到
SelectionKey
值。
- 拿到
- 通过第二步注册之后, 设置属性标识 《已注册》
- 通过
DefaultChannelPipeline
调用invokeHandlerAddedIfNeeded()
… 这个处理消息逻辑下面单独分析… - 指定的
DefaultChannelPromise
标记为成功。如果已经完成,那么记录一条消息 - 通过
DefaultChannelPipeline
调用fireChannelRegistered()
。 - 判断 管道是否打开, 以及管道是否
isBound()
. 这里是未绑定的. false。 所以先不分析里面的逻辑。
AbstractChannel$AbstractUnsafe 内部类的对象中. 注册逻辑
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "eventLoop");
if (isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
if (!isCompatible(eventLoop)) {
promise.setFailure(new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
}
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
logger.warn("Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
private void register0(ChannelPromise promise) {
try {
// 请检查通道是否仍然打开,因为当寄存器调用在 eventLoopFuture 之外时,通道可能会关闭,从而无法取消
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
// 设置ServerSocketChannel 注册选择器
doRegister(); // AbstractNioChannel#doRegister(): 使用ServerSocketChannel 注册到 Selector 得到 SelectionKey
// 设置标识为已注册
neverRegistered = false; // 绝不
registered = true;
// Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
// user may already fire events through the pipeline in the ChannelFutureListener.
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
// Only fire a channelActive if the channel has never been registered. This prevents firing
// multiple channel actives if the channel is deregistered and re-registered.
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// This channel was registered before and autoRead() is set. This means we need to begin read
// again so that we process inbound data.
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
/ AbstractNioChannel 类中方法 doRegister 注册逻辑
protected void doRegister() throws Exception {
boolean selected = false;
for (; ; ) {
try {
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
ChannelPipeline 处理 ChannelHandler
DefaultChannelPipeline 分析
先从这个 invokeHandlerAddedIfNeeded()
方法分析…
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
// We are now registered to the EventLoop. It's time to call the callbacks for the ChannelHandlers,
// that were added before the registration was done.
callHandlerAddedForAllHandlers();
}
}
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
registered = true;
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
this.pendingHandlerCallbackHead = null;
}
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute();
task = task.next;
}
}
DefaultChannelPipeline 中属性分析, 类中含 AbstractChannelHandlerContext
对象 head头部
和 tail尾部
AbstractChannelHandlerContext 双向链表分析:
默认实现为, DefaultChannelHandlerContext
内部类实现, HeadChannelHandlerContext
内部类实现, TailChannelHandlerContext
可以理解为双向链表. AbstractChannelHandlerContext
内部包含自身 next, prev 。 最主要的属性为 EventExecutor
对象, 事件执行器. 也可以说是一个线程。还有一些标记状态.
实现了 ChannelHandlerContext 接口, 该接口又继承了 ChannelInboundInvoker
和 ChannelOutboundInvoker
接口。
接口介绍
发现就是通过其ChannelHandlerContext 处理器上下文 处理信息传输。
通过单独的线程处理 传输任务。
分析完结… 后续整理