Jetty源码剖析系列(1)

Jetty是Eclipse Foundation出的一个轻量级Web服务器和Servlet容器。Spark使用了Jetty作为它的内嵌服务器。我一直都对Web服务器有着迷之兴趣,前前后后去读过好几个Web服务器的源码,有代码量太大设计模式复杂而半途而废的,如Tomcat,有因为代码量小而简单而读完的,如NanoHTTPD。相比之下,Jetty大小适中,而且也够成熟,之前在工作中写的一个项目就是用了Jetty Runner来实现了一个RESTful Service。这段时间重新去学习了一遍Java NIO,所以这次就趁机把Jetty的源码好好撸一遍。

Jetty Version: 9.4.5

Let's hit on the road!

Jetty Architecture

在开始剖析代码之前,我们先看一下Jetty的整体架构,Jetty的官方文档对Jetty架构有很详细的介绍(点这里)。

如文档所述:

The Jetty Server is the plumbing between a collection of 'Connector's that accept connections and a collection of 'Handler's that service requests from the connections and produce responses, with threads from a thread pool doing the work.

Connector负责接收网络请求,Handler负责解析请求并产生响应,通过线程池ThreadPool来执行任务,而Connector,Handler,ThreadPool这三个组件都是依附在Server中。

启动一个内嵌的Jetty服务器

本文开头提到过Spark就是用了Jetty做为它内嵌的服务器,从上文所看到Jetty是由Server,Connector,Handler,ThreadPool这几个组件组成,那我们来看一下如何启动一个内嵌的Jetty服务器。 是的,上面的代码就已经是启动了一个内嵌的Jetty服务器!(当然,有部分代码我已经省略)。仔细看一下,ServerConnectorHandler,都有了,那ThreadPool呢?我们看一下Server类的构造函数: 我们可以看到线程池是在Server的构造函数里面创建出来了,默认是一个QueuedThreadPool,基于队列的线程池。 实现一个线程池是一个不错的Java面试题,我们就先看一下Jetty是如何实现的。我们先看一下QueuedThreadPool的层级关系:
再看QueuedThreadPool的构造函数: 我们可以看到QueuedThreadPool是把Runnable的job放在一个org.eclipse.jetty.util.BlockingArrayQueue里,org.eclipse.jetty.util.BlockingArrayQueue是Jetty自己实现的基于数组的阻塞队列。 从前文QueuedThreadPool的层级关系图看到QueuedThreadPool实现了LifeCycle接口,这个LifeCycle接口在Jetty里面是一个非常重要概念,ServerConnectorHandler,和QueuedThreadPool都是实现LifeCycle接口。这些组件都会通过调用start()方法来启动,而start()方法最终又会调用doStar()方法。我们先来看QueuedThreadPool这个线程池是怎样启动的: 它先把_threadsStarted这个Atomic的变量设成0,然后启动_minThreads个线程: 可以看到,实际上它是启动了_minThreads个_runnable线程,而这个_runnable线程做的是什么的? 我们可以看到这个_runnable线程是去_jobs也就是BlockingArrayQueue这个队列里面取出一个Runnablejob,然后执行这个job:

To Be Continue......

comments powered by Disqus