Netty 4.1.58.Final 关键源码

博文目录


线程模型图 - Reactor 模型

在这里插入图片描述

服务端编程模板

public static void main(String[] args) {
	EventLoopGroup bossGroup = new NioEventLoopGroup(1);
	EventLoopGroup workerGroup = new NioEventLoopGroup();
	try {
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(bossGroup, workerGroup)
				.channel(NioServerSocketChannel.class)
				.option(ChannelOption.SO_BACKLOG, 1024)
				.childHandler(new ChannelInitializer<SocketChannel>() {
					@Override
					protected void initChannel(SocketChannel socketChannel) throws Exception {
						ChannelPipeline pipeline = socketChannel.pipeline();
						pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8));
						pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8));
						pipeline.addLast(new MyStringChannelInboundHandler());
					}
				});
		ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
		channelFuture.channel().closeFuture().sync();
	} catch (Throwable cause) {
		log.error("", cause);
	} finally {
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
	}
}

核心组件类图

NioEventLoopGroup 和 NioEventLoop

在这里插入图片描述
通过类图要明确如下两条父子关系链, 子的身份既是子也是父, 调用子类覆盖的父类的某些方法时, 可以从最低的级别向上找

  • NioEventLoopGroup > MultithreadEventLoopGroup > MultithreadEventExecutorGroup > AbstractEventExecutorGroup > EventExecutorGroup
  • NioEventLoop > SingleThreadEventLoop > EventLoop > EventExecutor

NioServerSocketChannel 和 NioSocketChannel

在这里插入图片描述

  • NioServerSocketChannel > AbstractNioMessageChannel > AbstractNioChannel > AbstractChannel
  • NioSocketChannel > AbstractNioByteChannel > AbstractNioChannel > AbstractChannel
  • AbstractNioMessageChannel里newUnsafe()新建的是NioMessageUnsafe实例, 即NioServerSocketChannel持有的unsafe是NioMessageUnsafe
  • AbstractNioByteChannel里newUnsafe()新建的是NioByteUnsafe实例, 即NioSocketChannel持有的unsafe是NioByteUnsafe

创建 NioEventLoopGroup

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
  • 记住: 当前创建的对象是NioEventLoopGroup, 即使调用父类的构造函数, 也是在给NioEventLoopGroup实例完善字段, 包括调用父类的方法, 也要认为是调用自己的方法
  • 入参没有指定nThreads, 则默认传0, 没有指定executor, 则默认传null, 先在NioEventLoopGroup中的各构造器之间跳转, 逐渐添加各种默认参数
  • 跳到抽象父类MultithreadEventLoopGroup的构造器中, 在这里判断有没有传入nThreads, 没有传入的话用默认值(CPU逻辑核数乘以2)
  • 跳到抽象父类MultithreadEventExecutorGroup的构造器中, 给 NioEventLoopGroup 的 children 和 chooser 属性赋值, children 的类型是 EventExecutor[], 其中的每一个项都是用子类 NioEventLoop 构建的
  • 构造NioEventLoop时, 传入了executor等参数, 给 NioEventLoop 的 selector 赋值
  • 跳到抽象父类SingleThreadEventLoop的构造器中
  • 跳到抽象父类SingleThreadEventExecutor的构造器中, 给 NioEventLoop 的 executor和taskQueue 属性赋值
  • 跳到抽象父类AbstractScheduledEventExecutor的构造器中
  • 跳到抽象父类AbstractEventExecutor的构造器中, 给 NioEventLoop 的 parent 属性 赋值为 NioEventLoopGroup 的实例

NioEventLoopGroup 和 NioEventLoop 的关系

初始化 NioEventLoopGroup 的时候, 有两个比较重要的属性, 如下

// EventExecutorGroup 中维护的一组 EventExecutor
private final EventExecutor[] children;
// EventExecutorGroup.next() 方法依赖该选择器选择合适 EventExecutor 来执行任务
private final EventExecutorChooserFactory.EventExecutorChooser chooser;

其中 children 本质上是 NioEventLoop 数组实例, chooser 持有 children 的引用, 其 next() 方法可以从 children 中轮询出一个 NioEventLoop 实例来做其他操作. 从 NioEventLoopGroup 中获取一个 NioEventLoop 实例就是通过 chooser 的 next() 方法取到的. 这里有一个小优化点, chooser 在初始化时根据 nThreads 是否是2的指数, 初始化不同的实例, 都是轮询取出 child, 不过2的指数时使用了(x&(n-1))方式(n是2的指数次)来提升性能

创建并装配 ServerBootstrap

ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
		.channel(NioServerSocketChannel.class)
		.option(ChannelOption.SO_BACKLOG, 1024)
		.childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel socketChannel) throws Exception {
				ChannelPipeline pipeline = socketChannel.pipeline();
				pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8));
				pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8));
				pipeline.addLast(new MyStringChannelInboundHandler());
			}
		});
  • group(bossGroup, workerGroup), 给group和childGroup属性赋值
  • channel(NioServerSocketChannel.class), 通过传入的channelClass, 给channelFactory属性赋值, 用于创建服务端channel, 这里用的是NIO的ServerSocketChannel的封装, NioServerSocketChannel.class
  • option(ChannelOption.SO_BACKLOG, 1024), 给通道属性options设置相关的属性
  • childHandler(new ChannelInitializer), 给childHandler属性赋值, 注意initChannel方法中添加的handler都是给SocketChannel用的而不是ServerSocketChannel

绑定端口

ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();

在这里插入图片描述

Netty事件注册过程

selectionKey = javaChannel().register(eventLoop().selector, 0, this);

这篇文章解释了为什么 ServerSocketChannel 注册 accept 事件到 Selector 时为什么传入的感兴趣的事件不是 OP_ACCEPT(16) 而是 0, 这点和直接使用NIO相差很大. 其实这个地方注册的0并不是Selector真正感兴趣的事件, 而是在后面当 ServerSocketChannel 实例成功绑定端口后, 才将 register 的返回值的 SelectionKey 实例的感兴趣事件重新设置成 16, 这时 Selector 实例才真正开始处理 ACCEPT 事件

客户端连接服务端

服务端启动好后, 等待客户端连接, 当客户端连接后, 服务端 unsafe.read() 会收到ACCEPT(16)事件, 走accept流程
在这里插入图片描述

客户端向服务端写数据

客户端和服务端建立连接, SocketChannel建立好后, Selector等待客户端向SocketChannel中写数据, unsafe.read() 会收到READ(1)事件, 走read流程
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
包含最新版文档以及全部jar包: jar包如下 netty-buffer-4.1.32.Final-sources.jar netty-buffer-4.1.32.Final.jar netty-build-22-sources.jar netty-build-22.jar netty-codec-4.1.32.Final-sources.jar netty-codec-4.1.32.Final.jar netty-codec-http-4.1.32.Final-sources.jar netty-codec-http-4.1.32.Final.jar netty-codec-http2-4.1.32.Final-sources.jar netty-codec-http2-4.1.32.Final.jar netty-codec-memcache-4.1.32.Final-sources.jar netty-codec-memcache-4.1.32.Final.jar netty-codec-redis-4.1.32.Final-sources.jar netty-codec-redis-4.1.32.Final.jar netty-codec-socks-4.1.32.Final-sources.jar netty-codec-socks-4.1.32.Final.jar netty-codec-stomp-4.1.32.Final-sources.jar netty-codec-stomp-4.1.32.Final.jar netty-common-4.1.32.Final-sources.jar netty-common-4.1.32.Final.jar netty-example-4.1.32.Final-sources.jar netty-example-4.1.32.Final.jar netty-handler-4.1.32.Final-sources.jar netty-handler-4.1.32.Final.jar netty-handler-proxy-4.1.32.Final-sources.jar netty-handler-proxy-4.1.32.Final.jar netty-resolver-4.1.32.Final-sources.jar netty-resolver-4.1.32.Final.jar netty-tcnative-2.0.20.Final-osx-x86_64.jar netty-tcnative-2.0.20.Final-sources.jar netty-transport-4.1.32.Final-sources.jar netty-transport-4.1.32.Final.jar netty-transport-native-epoll-4.1.32.Final-linux-x86_64.jar netty-transport-native-epoll-4.1.32.Final-sources.jar netty-transport-native-kqueue-4.1.32.Final-osx-x86_64.jar netty-transport-native-kqueue-4.1.32.Final-sources.jar netty-transport-native-unix-common-4.1.32.Final-sources.jar netty-transport-native-unix-common-4.1.32.Final.jar netty-transport-rxtx-4.1.32.Final-sources.jar netty-transport-rxtx-4.1.32.Final.jar netty-transport-sctp-4.1.32.Final-sources.jar netty-transport-sctp-4.1.32.Final.jar netty-transport-udt-4.1.32.Final-sources.jar netty-transport-udt-4.1.32.Final.jar
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值