我们先来回顾一下 Jetty
负责网络连接的类 ServerConnector
的构造函数: 可以看到在ServerConnector的构造函数里会创建一个 SelectorManager
,然后加到它的bean里面(这里其实体现了Jetty的一个设计模式,就是设计了一个containner,把相关的模块放到这个containner里面,启动该container(调用doStart方法)就会连带启动里面的模块(调用模块的doStart方法), Jetty里面的Server,Connector都是这样的containner。)
我们再来看newSelectorManager方法: 就是创建一个ServerConnectorManager对象,ServerConnectorManager继承了SelectorManager类: ,我们再看一下SelectorManager的doStart方法: 可以看到在调用父类的doStart方法之前,会创建ManagedSelector,并将该selector加到SelectorManager的bean里面,随后再在调用父类的doStart方法时调用该selector的doStart方法,注意selector的数目是根据CPU的数量计算出来的, newSelector方法其实就是直接构建一个ManagedSelector对象: 我们看一下ManagedSelector的构造函数: 关于ManagedSelector,我在系列(4)里面已经有详细剖析。
此时我们先回过头去看一下ServerConnector的doStart方法: 它先调用open方法打开ServerSocketChannel,这个我在系列(6)里面有详细剖析。我们这里关注一下它调用的父类的doStart(AbstractConnector)方法: 它先调用了父类ConntainnerLifeCycle的doStart方法将它所拥有的bean(模块)都启动起来,其中就包括了我们前面加进去的SelectorManager,随即也就会把SelectorManager里面的ManagedSelector启动起来(调用它的doStart方法)。到此,我们可以看到ServerConnector会先启动Selector,然后再启动Acceptor。Connector,Selector,Acceptor,这三者的关系我画了下图来说明: 从上图可以看到,Acceptor负责接收网络连接,封装成一个channel,然后把该channel注册到Selector,由selector来monitor这个channel的状态是Readable还是Connectable还是Writable, 针对不同的状态来做不同的事,比如readable的时候,也就是TCP的receive buffer里面有发送给某个socket的数据时,tcp就会通知application来读取。其实以上所说的这些,都是标准的NIO的操作,与编程语言无关,与容器框架也无关,而Jetty也只是实现了这个标准的NIO操作而已。
Acceptor实现了Runnable接口,它是被扔到QueuedThreadPool线程池里面执行的:
Acceptor的run方法里面循环调用了accept方法:
值得注意的是,serverChannel的accept方法调用是blocking的,就是说直到有一个connect请求过来它才会返回,当然,这个是可配置的(其实它就是在ServerConnection open这个serverChannel的时候就设置成blocking的了),当接收到一个connect请求后,返回一个socketChannel对象,然后就调用accepted方法,我们注意看accepted方法里面最后那句,_manager.accept(channel)
, 这个
_manager
就是我们上文说到的SelectorManager,我们再看它的accept方法:
到此,我们就清楚地看到Selector跟Accptor是如何联系到一起了,当然这里的Selector是封装后的Selector,我们先看一下它的submit方法:
这个方法核心的部分是这句:
_updates.offer(update)
,
_updates
是一个
ArrayDeque<SelectorUpdate>
,就是说submit方法会把一个SelectorUpdate对象塞到一个Deque里面,那我们再来看一下这个SelectorUpdate对象是什么:
到此,我们先来总结一下,就是Acceptor接收到一个connect请求后,会封装出一个Accept对象,这个对象实现了SelectorUpdate接口,然后把这个Accept对象塞到ManagedSelector的一个ArrayDeque里面,其实这里就是体现上文中的那个图,接收到connect请求后,封装好channel,交给Selector去monitor它的状态,就是说接下来的事就由Selector来handle了,在看ManagedSelector的doStart方法前,我们先来回顾一下它的构造函数: 我们看到它把一个EatWhatYouKill对象加到它的bean里面,那就意味着在启动ManagedSelector时也会启动这个EatWhatYouKill对象(调用它的doStart方法),同样我们先来看一下EatWhatYouKill的构造函数: 一样的套路,它把一个Producer对象加到它的bean里面了,这个Producer是上ManagedSelector的构造函数里面创建出来传给EatWhatYouKill的构造函数的,SelectorProducer对象。
这个时候就可以来看一下ManagedSelector的doStart方法了: 它先调用的父类的doStart方法,其实就是去启动它前面添加的beans(递归调用bean的doStart方法),然后通过 selectorManager的newSelector方法打开一个真正的Selector对象: 然后就通过线程池去执行了EatWhatYouKill的的produce方法(这里用的是Java8的语法,而一个方法其实就是一段可执行的字节码,自然是runnable的): 这里核心的是tryProduce方法里面循环调用的doProduce方法: 这个方法比较长,我们看核心的,先看它调用的produceTask方法是生产了什么东西: 它调用的 producer的produce方法,_producer是上文提到的SelectorProducer对象,它的produce方法: (未完待续。。。。。。。)