首先看一段Netty服务端启动的代码:
1 | // EventLoopGroup线程组 |
- 创建了bossGroup和workerGroup,它们都是EventLoopGroup类型的
- 创建了ServerBootstrap启动类
- 为ServerBootstrap设置EventLoopGroup、Channel类型、端口和ChannelHandler
- ServerBootstrap绑定端口并且启动服务
以ServerBootstrap的bind方法为入口,看下Netty服务的启动过程。
ServerBootstrap
ServerBootstrap是AbstractBootstrap的子类,bind方法在AbstractBootstrap中实现,主要包含了两件事情:
- 创建Channel并完成Channel的初始化与注册
- 将channel进行端口绑定
1 | public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable { |
Channel的初始化与注册
- 创建Channel
- 初始化channel
- 注册Channel
1 | final ChannelFuture initAndRegister() { |
创建Channel
ChannelFactory
ChannelFactory是一个接口,从名字上可以看出它是创建channel的一个工厂,通过DEBUG可以看出使用的ReflectChannelFactory进行channel创建的,进入ReflectChannelFactory,可以看到通过Constructor进行Channel创建的:
1 | public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> { |
那么这个Constructor是在什么时候传入的呢,回到最开始的代码,可以看到为ServerBootstrap设置了channel类型,类型为NioServerSocketChannel:
1 | ServerBootstrap b = new ServerBootstrap(); |
进入ServerBootstrap的channel()方法,可以看到创建了ReflectiveChannelFactory,并且设置了channel类型:
1 | public abstract class AbstractBootstrap { |
总结:
1.ServerBootstrap会设置Channel的类型,选择创建什么类型的Channel。
2.使用ChannelFactory(ReflectChannelFactory实现),根据设置的channel类型,通过反射创建出NioServerSocketChannel,完成Channel的创建。
NioServerSocketChannel
NioServerSocketChannel中的构造函数可以看出是通过SelectorProvider创建channel的:
- 构建NioServerSocketChannel的时候指定SelectorProvider,就通过指定的SelectorProvider来创建
- 如果没有指定SelectorProvider,那么就通过调用SelectorProvider的provider()方法返回一个SelectorProvider
- 调用SelectorProvider的openServerSocketChannel完成channel的创建
1 | public class NioServerSocketChannel extends AbstractNioMessageChannel |
SelectorProvider
SelectorProvider是JDK中的一个抽象类,provider()方法中,有三种方式创建SelectorProvider:
loadProviderFromProperty()方法
调用JVM的系统配置,获取环境配置信息,判断是否配置了java.nio.channels.spi.SelectorProvider参数,如果配置了,就使用配置的SelectorProvider实现类进行创建。
loadProviderAsService()方法
通过SPI机制查找配置的ServiceLoader实现类。
使用DefaultSelectorProvider创建
默认的SelectorProvider,不同的操作系统下JDK的代码也不一样。
1 | public abstract class SelectorProvider { |
DefaultSelectorProvider
操作系统和版本的不同,DefaultSelectorProvider返回的SelectorProvider也不同,比如我的电脑是MAC操作系统,在create方法中返回的就是KQueueSelectorProvider:
1 | public class DefaultSelectorProvider { |
看下DefaultSelectorProvider在Linux操作系统下的create方法实现:
1 | public static SelectorProvider create() { |
总结:根据操作系统和版本可以创建出不同类型的SelectorProvider,比如Linux下使用的是EPollSelectorProvider、SunOS下使用的是DevPollSelectorProvider。
初始化Channel
回到initAndRegister中的init方法,看下Channel的初始化过程,init方法是在ServerBootstrap中实现的,初始化工作主要是设置一些参数、为ChannelPipeline设置处理器等:
1 | public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> { |
注册Channel
回到AbstractBootstrap的initAndRegister方法,可以看到是调用EventLoopGroup的register方法进行channel注册的,它会从EventLoopGroup选择一个EventLoop与channel进行绑定:
1 | // AbstractBootstrap |
最终会调用到AbstractChannel的register方法进行channel的注册,中间的跳转过程如下:
1 | // 1. MultithreadEventLoopGroup实现了register方法, |
AbstractChannel
AbstractChannel的register方法:
1 | public abstract class AbstractChannel extends DefaultAttributeMap implements Channel { |
AbstractNioChannel
doRegister是在AbstractNioChannel中实现的:
- this.javaChannel()返回了ServerSocketChannel,具体类型是sun.nio.ch.ServerSocketChannelImpl,它是JDK中的类
- this.eventLoop().unwrappedSelector()返回了EventLoop中的Selector
- 调用了JDK底层的方法,将当前的channel绑定到了EventLoop中的Selector
1 | public abstract class AbstractNioChannel extends AbstractChannel { |
端口绑定
回到AbstractBootstrap的doBind0方法,这里实现了端口的绑定,跟着断点最终会进入到NioServerSocketChannel的bind方法,又是调用了JDK底层的方法进行端口的绑定。
1 | public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable { |
Accept事件监听
在AbstractChannel的bind方法中,端口完成绑定后会判断Channel的活跃状态,然后调用fireChannelActive触发Channle活跃的事件,跟着断点最终会进入到AbstractNioChannel的doBeginRead方法:
1 | // 绑定完成后,Channel处于活跃状态 |
NioServerSocketChannel的构造函数中,初始化了readInterestOp为SelectionKey.OP_ACCEPT,所以在doBeginRead中,OP_ACCEPT事件会被注册到Channel的事件集合中。
1 | //NioServerSocketChannel |
Netty版本:4.1.42.Final
参考: