应用技术--容器-jetty

Jetty

_ Jetty 是一个开源的servlet容器,使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立运行的Java应用提供web连接。jetty相较tomcat会更加的轻量级,也更加的灵活。因而也逐渐受到了众多企业的青睐。 本文不会一一介绍jetty的各个方面的特性,因为jetty默认以NIO方式来处理请求,所以本文以NIO为切入点,来探讨一下jetty处理请求的过程。 本文首先会介绍一下NIO的基本概念以及jetty的整体架构作为基础,然后介绍处理请求过程中的核心类和jetty接收处理请求的全过程。_

1.Jetty的整体架构

jetty主要有两个核心组件connector和handler构成,如下图1所示。Connector 负责监听接收客户连接请求,而 handler 组件则负责处理请求并给予响应。前面两个组件工作所需要的线程资源都直接从线程池(ThreadPool) 中获取,所有实现了Runnable接口的可执行任务都通过该线程池统一调度。

图1 jetty整体架构图

2.NIO简介

2.1 NIO的核心概念

NIO对于传统的I/O的改进主要是通道(channel),缓冲区(buffer)和选择器(selector)。Java NIO的通道类似流,但流的读写通常是单向的。我们可以从通道中读取数据,又可以写数据到通道,而且通道支持异步地读写。通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。缓冲区本质上是一块可以写入数据,也可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问这块内存。 Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便,如图2。

图2 selector结构

2.2 jetty中的NIO

以前的阻塞I/O的方式是客户端的每一次请求在服务器端开一个新的线程来进行响应,read/write的操作都是阻塞的,无论客户端有没有数据的响应,这个线程始终是开着的,CPU会不断的轮询这些线程,而且线程之间的切换的开销比较大。

NIO非堵塞技术实际是采取Reactor模式如下图3所示,时刻监听着I/O端口,如果有内容进来,会自动通知我们,这样我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,而且也不堵塞了。

如图3 Jetty的NIO模式

mainReactor:jetty从线程池中分配一个线程专门用来接收用户的请求(accept()方法)

ServerSocketChannel server;synchronized(this)                    {                        server = _acceptChannel;                    }if(server!=null&& server.isOpen() && _manager.isStarted())                    {                        SocketChannel channel = server.accept();                    }

subReactor:subReactor负责多路分离已连接的channel,调用select线程,轮询注册进来的 channel。读 写网络数据,扔给worker线程池来处理。其中最主要的类是selectManager,selectManager中包含着一个selectSet的数组,每个SelectSet对象可以参见图2的结构特征,包含一个selector对象和changes数组。这里面将SelectSet设计为一个数组,应该也是分而治之的思想,让一个selector监听更少的selectionkey,那么相应的提高了并发处理的能力。

acceptor: 在接收到用户请求后,对socket进行一些配置,然后将SocketChannel注册到 selector中

| public class SelectSet implements Dumpable { private final ConcurrentLinkedQueue _changes = new ConcurrentLinkedQueue();

private volatile Selector _selector; }

|

ThreadPool:线程池比较简单,其中mainReactor与subReactor共用同一个线程池,线程池的实现类是 QueuedThreadPool

3.jetty对于请求的接收过程

3.1 核心方法的介绍

Connector:Connector组件是Jetty中可以直接接受客户端连接的抽象,一个Connector监听Jetty服务器的一个端口,所有客户端的连接请求首先通过该端口,而后由操作系统分配一个新的端口(Socket)与客户端进行数据通信(先握手,然后建立连接,但是使用不同的端口)。下图4是conncetor组件的核心类SelectChannelConnector的类图。

图4 SelectChannelConnector的类图

SelectManager:持有SelectorSet,其中SelectSet封装了NIO中的Selector,增强了其功能,也起到了负载均衡的效果。

SelectSet:在类selectSet 中,都包含一个Selector和一个change的队列,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据。

3.2 jetty请求建立

jetty 请求建立的过程时序图,见图5。

图5 jetty接受请求

server首先利用SelectChannelConnector,调用open()方法,创建ServerSocketChannel,配置其为阻塞模式,并设置localPort值。然后在doStart()方法中,它会初始化SelectManager,并启动该Manager,启动多线程,不断的调用Manager的doSelect方法。然后启动多个Acceptor线程去接收客户端的请求,有请求时就将SocketChannel注册到SelectorManager,最终由上面的select线程来处理请求。

4.jetty对于请求的处理过程

4.1 核心方法的介绍

EndPoint:在Connector启动时,它会启动多个acceptor线程用于监听在Connector中配置的端口。对于客户端的每次连接,Connector都会创建相应的EndPoint来表示该连接,EndPoint用于和Socket打交道.EndPoint最主要的方法从底层传输链路中读取数据并填入Buffer中的fill方法,以及将Buffer中的数据写入底层传输链路的flush方法。

connection:Connection用于在从Socket中读取到数据后的处理逻辑以及生成响应数据的处理逻辑,HttpConnection是Jetty中对Connection的主要实现,它表示Http客户端和服务器的一次连接,用于将Request、Response、EndPoint联系在一起。

HttpParse:Jetty使用Parser(HttpParser)来抽象HTTP请求消息和响应消息的解析类引擎。从缓存池中取缓存,将channel的请求数据读取到缓存中,并解析成Request。

HttpBuffers: 缓存池

4.2 jetty请求处理过程

图6 分配业务线程

建立好连接之后,当有数据发过来的时候,selector会监测到SocketChannel上的读的事件,接下来会创建EndPoint来表示这次连接,同时生成一个HttpConnection对象,为解析请求和handle请求准备好环境。当读事件就绪的时候,调用endpoint的schedule()方法,这个方法的主要的目的是从线程池中分配一个worker的线程来处理这个read的事件见图6。然后立刻再去监听事件,非常的简单高效。

图7 请求解析和处理

当业务线程分配成功以后,则主要是一方面负责请求的读取,将数据从socketChannel 中读取到buffer中,见图7。一方面是对请求进行解析,生成request,如果请求是完整的,那么就开始调用Server的handle()方法,处理这个request。

**   总结**:受限于能力水平,本文只是简单了介绍了jetty基于NIO的请求解析的流程,很多细节没有涉及到,希望大神们感兴趣的多多指点和补充。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容