Jetty9源码剖析 - Connector组件 - ManagedSelector

一、概念

ManagedSelector是一个托管的Selector,它包装了NIO中的Selector,并在内部完成select事件监听处理

二、继承体系

可以看到ManagedSelector是具有生命周期的,继承体系比较简单

三、总体架构

图中绿色表示ManagedSelector相关的组件,其中EPC内绿色部分属于ManagedSelector内部的类SelectorProducer,ManagedSelector启动的时候会运行ExecutionStrategy.execute,让EPC开始运行,而在EPC内部会运行ManagedSelector内部类的SelectorProducer来执行相关的select操作,完成读写事件的处理(EPC将会在后面讲解)

四、源码剖析

1. 构造函数

构造函数比较简单,strategy默认使用SelectorProducer来作为生产者,这个类是ManagedSelector的内部类,ExecutionFactory默认会创建ExecuteProduceConsume,即EPC作为任务执行器

2. 启动

启动很简单,开一个新的Selector,newSelector实际就是Selector.open调用,然后将当前ManagedSelector扔到SelectorManager的Executor里面执行

可以看到ManagedSelector提供的run方法其实就是执行了ExecuteProduceConsume.execute,让EPC开始执行生产消费任务

3. 连接处理与事件注册

前面的SelectorManager其实已经讲解到了选择了一个ManagedSelector后,会使用ManagedSelector.submit方法,将上图中的Accept动作放到_actions列表执行,这个将会被后续的EPC利用SelectorProducer执行拿到,就会执行Accept.run方法,可以看到是首先注册了一个0的interestOps,也就是什么也不监听(为啥这里注册为0?其实这里对于Jetty来说,很多东西都还没准备好,例如EndPoint和Connection都没建好,所以暂时并不能处理数据的读写,因此不监听事件),之后再向_actions提交一个CreateEndPoint的动作,开始创建EndPoint

 

run方法可以看到是执行createEndPoint,使用了SelectorManager来创建EndPoint和Connection,前面SelectorManager已经讲解过了,这里不再赘述
之后会将EndPoint关联上Connection,EndPoint顾名思义其实就是端点,端点需要和连接打通,这样才能形成真正意义上的一条数据通道
selectionKey.attach会将当前的这个SocketChannel的SelectionKey关联上这个创建出来的EndPoint

之后触发SelectorManager的端点完成操作、连接完成操作
在端点完成操作里面会将当前的SelectionKey的interestOps切换为OP_READ,注册上读事件,这样后续就能处理读数据
在连接完成操作里面会将当前Connection的回调注册到EndPoint的_fillInterest,也就是说当数据到来时会触发这个_fillInterest的回调,从而调用到HttpConnection的onFillable,这样就打通了端点事件到连接的数据操作(EndPoint和Connection将在后续章节详细讲解)

4. 数据读写

EPC会调用生产者生产任务,也就是这里的SelectorProducer.produce,生产完成后,会根据分派类型(dispatch)来执行任务,通常是在同一个线程执行任务,如果dispatch是要求新的线程,才会放到另一个线程,下一节会详细讲解EPC的执行逻辑,这里不再多讲

首先看produce方法,他会执行我们之前画的图中的几个步骤,分别是:processSelected、runActions、update、select

 

processSelected会判断看当前是否有准备好的事件,如果当前有事件发生,则判断是否是SelectableEndPoint,也就是是否是读写事件,如果是读写事件会触发SelectableEndPoint.onSelected(),通常就是我们的SelectChannelEndPoint执行(这个组件会在后续详细讲解),在它的onSelected会返回一个读或者写或者读写的任务

我们还可以看到其实它还可以处理连接的接入,这其实就是之前我们说的用户指定ServerConnector的acceptors=0,就会让ManagedSelector来执行接入

 

runActions会从_actions队列拿到任务,然后执行,前面我们说的连接的接入时,会触发submit一个Accept动作,这个动作就会被放到_actions队列,让这个EPC来执行

接下来是update的执行,update会拿到select出来的SelectionKey列表,然后去更新它们对应的感兴趣的事件(详细的会在EndPoint讲解),例如当前需要写入操作,后续会将这个SelectionKey的interestOps改成OP_WRITE,这样就能写入数据到Channel,当没有数据写入时会移除SelectionKey的OP_WRITE操作,这样动态切换读写操作

select就是阻塞等待新的事件到来,如果Selector检测Channel有事件发生或者被wakeup,这里就会返回,并将发生事件的Channel的SelectionKey列表拿到,逻辑相对还是比较简单

这就是SelectorProducer执行的核心逻辑,produce来生产任务,能完成事件检测、读写切换、动作(连接、销毁、关闭等等)执行

五、 总结

ManagedSelector逻辑也不算复杂,主要就是结合了EPC这个执行操作,让原本简单的事件检测循环看起来很绕,不过静下心来看,还是可以理解的。相信大部分读者在读到这篇文章的时候,对EPC感到困惑,EPC到底来干什么,按照常规的NIO玩法,不就是一个while循环+select操作就能完成的事情,在这里被玩得这么复杂了,这个答案将会在接下来的EPC章节讲解,欢迎大家持续关注~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值