ServerBootstrap用于关联服务端的各组件
回顾服务端代码和netty的reactor模型,可以看到出,parentGroup用来处理连接请求,childGroup用于处理接下来的操作
new 方法并没有什么操作,服务端关联组件ServerBootstrap, 继承于AbstractBootstrap,父子类的group、options、attr、handler变量,对应parentGroup和childGroup
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
// 这个config就是用来获取当前对象的各种配置,childGroup、childHandler、attr等等
private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
private volatile EventLoopGroup childGroup;
private volatile ChannelHandler childHandler;
public ServerBootstrap() {
}
}
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
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() {
}
}
bootstrap.group(parentGroup, childGroup)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
这三步不看代码了,字面意思,就是赋值到对应的变量上
.channel(NioServerSocketChannel.class)
// 初始化channel工厂,内部newChannel()方法,调用会new一个新的NioServerSocketChannel
io.netty.bootstrap.AbstractBootstrap.channel(Class<? extends C>)
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
// 返回一个channelFactory
return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
if (channelFactory == null) {
throw new NullPointerException("channelFactory");
}
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
this.channelFactory = channelFactory;
return this;
}
//io.netty.channel.ReflectiveChannelFactory#newChannel
public T newChannel() {
try {
// 使用反射机制,调用其无参构造器,创建channel
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
new NioServerSocketChannel();
NioServerSocketChannel就是原生ServerSocketChannel的封装
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
private static java.nio.channels.ServerSocketChannel newSocket(SelectorProvider provider) {
try {
// 这就是原生NIO代码中获取Server端Channel的代码ServerSocketChannel.open()底层
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException("Failed to open a server socket.", e);
}
}
public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) {
// 有设置channel非阻塞,初始化pipeline(DefaultChannelPipeline),unsafe类等操作
super(null, channel, 16);
config = new NioServerSocketChannelConfig(this, javaChannel().socket(), null);
}
protected AbstractChannel(Channel parent) {
this.parent = parent;
// 为Netty的channel生成id
id = newId();
// 底层操作对象 AbstractNioMessageChannel.NioMessageUnsafe对象
unsafe = newUnsafe();
// 创建当前channel所绑定的channelPipeline ,DefaultChannelPipeline对象
pipeline = newChannelPipeline();
}
.childHandler,字面意思,为childHandler赋值,先不解释ChannelInitializer,内部pipeliine.addLast并没执行,下边执行的时候再跟
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new RpcServerHandler(registerMap));
}
});
ChannelFuture future = bootstrap.bind(8888).sync();
在原生NIO编程中,初始化的时候有两步,绑定端口号和注册channel连接事件到selector
socketChannel.bind(new InetSocketAddress(8080));
socketChannel.register(selector,SelectionKey.OP_ACCEPT);
bind(8888)中就是做这两步,对应就是initAndRegister()方法和doBind0()方法,主要关注这两
// 直接看核心代码
// 注册和绑定端口是另开一个线程去操作,所以会返回一个异步结果对象ChannelFuture()来关联异步结果
// 外界判断异步操作是否完成,isDone()
// bind(8888).sync()的sync方法也是阻塞线程,直到这个Promise对象已经被标识完成
private ChannelFuture doBind(final SocketAddress localAddress) {
// 创建、初始化channel,并将其注册到Selector
final ChannelFuture regFuture = initAndRegister();
// 从异步结果中获取channel
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.
// 创建一个可修改的异步结果对象channelFuture
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()
创建了ServerSocketChannel,并初始化,然后注册到parentGroup中(挑选一个NioEventLoop注册,一个Channel绑定一个NioEventLoop,一个NioEventLoop可以被多个Channel绑定)
关注点放在 init(channel)初始化channel 和 NioeventLoop.register(channel)注册NioServerSocketChannel
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// 创建一个channel new NioServerSocketChannel
channel = channelFactory.newChannel();
// 初始化NioServerSocketChannel
init(channel);
} catch (Throwable t) {
// 忽略了部分代码,报异常后直接返回失败的Promise
}
// config().group()获取了ServerBootStrap父类中的group,即我们代码的parentGroup
// 将当前channel注册给selector
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
// NioEventLoopGroup继承MultithreadEventLoopGroup
// io.netty.channel.MultithreadEventLoopGroup#register(io.netty.channel.Channel)
public ChannelFuture register(Channel channel) {
// 从parentGroup中根据算法选择一个NioeventLoop来完成注册
return next().register(channel);
}
doBind0
获取channel绑定的那个NioEventLoop, 用内部绑定的线程来绑定
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
全放在一块太乱了,我分开写了
总结之,serverBootStrap.bind(),分为两步
一、创建channel并注册channel到selector,其中又分为
1)初始化channel -- Netty服务端源码阅读笔记(四)ServerBootstrap(2)
2)NioEventLoop注册channel -- Netty服务端源码阅读笔记(四)ServerBootstrap(3)
二、为channel绑定端口号 -- Netty服务端源码阅读笔记(四)ServerBootstrap(4)