Jetty 源码分析
一、 总括 你了解Jetty 吗,就像我们所熟知的Tomcat一样, Jetty是一个免费的开放源码的100%纯Java的Http服务器和Servlet容器。
|
|
Jetty具备以下特点: |
|
快速高效
|
|
。Jetty是最快的Servlet服务器之一 |
|
。Jetty可以处理上千个并发连接 | |
小巧嵌入 | |
。Jetty的jar只有600多K | |
。可动态嵌入到应用程序,适合开发web2.0等应用 | |
应用广泛 |
|
。商业项目有IBM Tivoli, Sonic MQ and Cisco SESM等 |
|
可到Jetty网站http://jetty.mortbay.org/jetty/ 查看最新信息 |
|
本文将通过对Jetty最新稳定版 Jetty5.1.5RC2 源码的研究,向读者展示Jetty在设计方面使用的不同设计理念, 希望对广大开发者在设计自己的系统时有所帮助。 | |
Jetty按照功能可以分为四个主个主要的部分,HttpServer, HttpContext,HttpHandler,HttpListener,详见如下类图: |
|
<图 1-1> |
|
二、HttpServer及配置 |
|
对于初次接触Jetty的人一定会对上图感到迷惑,其实在Jetty中 HttpServer是一个服务器的核心控制类, 我们可以看到,其它的组件类都是由该类扩展开来,HttpServer的作用就是在一系列的监听器类和处理器类之间搭起了一个桥梁,有效的控制着消息在系 统内的传递,如下图: | |
<图 1-2 >
|
|
HttpServer职责是接受从HttpListener传递过来的request(请 求),HttpServer通过对request的Host(主机)或Path(路径)进行匹配,然后分发给相应的HttpContext(可以理解为一 个web application)。 | |
这里举个例子,假设我们现在要建立一个提供静态页面web服务,页面内容在c:\root \下,可以通过如此配置HttpServer: | |
HttpServer server = new HttpServer(); // 创建一个新的HttpServer | |
SocketListener listener = new SocketListener(); // 创建一个新监听器 | |
listener.setPort(8080);// 设置监听端口为8080 | |
server.addListener(listener);// 将监听类注册到server中 | |
HttpContext context = new HttpContext(); // 创建一个新HttpContext | |
context.setContextPath("/app/*"); // 设置访问路径 | |
context.setResourceBase("c:/root/"); // 设置静态资源路径 | |
context.addHandler(new ResourceHandler()); // 为这个HttpContext添加一个静态资源处理器 | |
server.addContext(context); // 将这个HttpContext注册到server中 | |
server.start();// 最后启动这个server | |
当我们要建立一个提供动态页面web服务时, 假设我们自己的 web 应用放在Jetty目录下的webapps下并打好包文件名为myapp.war, 可以通过如此配置HttpServer: | |
Server server = new Server(); // 创建一个新的HttpServer | |
SocketListener listener = new SocketListener();// 创建一个新监听器 | |
listener.setPort(8080); // 设置监听端口为8080 | |
server.addListener(listener ); // 将监听类注册到server中 | |
server.addWebApplication("myapp","./webapps/myapp/"); // 将这个web应用注册到这个Server中 | |
server.start(); // 最后启动这个server | |
短短数行代码就可创建一个web服务器并启动它,这有点类似于我们windows中的即插 即用的概念,需要什么就添加什么,把这些类以HttpServer为核心组合在一起,就可以完成强大的功能。 | |
三、Jetty Server |
|
1.上面我们探讨了HttpServer的启动,读者一定还存在这样疑问,整个Jetty 服务器是怎样启动的? | |
首先我们可以在图 1-1 看到左下角有一个Server类,这个类实际上继承了HttpServer,当启动Jetty服务器时,具体来说,在Jetty根目录下命令行下如输入 java -jar start.jar etc/demo.xml,注意这里有一个配置文件 demo.xml做为运行参数,这个参数也可以是其它的配置文件,也可是多个xml配置文件,其实这个配置文件好比我们使用struts时的struts -config.xml文件,将运行Server需要用到的组件写在里面,比如上一节中HttpServer的配置需要的组件类都可以写在这个配置文件 中。 | |
2.我们自己部署到Jetty的webapps目录下的web application,Jetty如何运行我们自己的web application? | |
首先当我们按上述方法启动Jetty Server时,就会调用Server类里面的main方法,这个入口方法首先会构造一个Server类实例(其实也就构造了一个 HttpServer),创建实例过程中就会构造XmlConfiguration类的对象来读取参数配置文件,之后再由这个配置文件产生的 XmlConfiguration对象来配置这个Server,配置过程其实是运用Java的反射机制调用Server的方法并传入配置文件中所写的参数 来向这个Server添加HttpListener,HttpContext,HttpHandler,web application(对应我们自己部署的web应用)。 | |
添加我们自己的web application过程中相应的就会读取我们所熟知的/WEB-INF/web.xml来创建一个WebApplicationContext(这个 类继承了HttpContext)的实例,同时也会创建WebApplicationContext自身的ServletHandler(实现了 HttpHandler接口),注意到ServletHandler中包含一组ServletHolder指向实际的Servlet,譬如说我们在 web.xml文件中配置了两个Filter和一个Servlet,这里就会有三个ServletHolder,实际处理请求时 ServeletHandler就会依次调用这三个ServletHolder传入request,response处理(实际最后交给这两个 Filter和Servlet处理),这样我们自己做好的一个 web应用就挂载到这个Server上了,可以接受客户端相应的request(请求)。 | |
四、运行原理(请参考如下时序图) |
|
<图 1-7 > |
|
上图展示了一个request的处理过程,首先HttpListener监听到客户端发来 的请求创建一个HttpConnection实例(封装了连接细节,比如从Socket连接中获取的输入流和输出流), HttpConnection对象构建过程中会创建Jetty内部自定义的HttpRequest和HttpResponse对象,接着 HttpListener会调用这个HttpConnection实例的handle方法, HttpConnection实例就调用HttpRequest对象的read()方法读取信息,调用HttpServer的service方法以 HttpRequest,HttpResponse为参数传给HttpServer,HttpServer又将HttpRequest和 HttpResponse分发给相应的HttpCotext,HttpContext最后将HttpRequest和HttpResponse交给自身的 HttpHandler 处理,在这里HttpRequest,HttpResponse被再次封装为ServletHttpRequest和 ServletHttpResponse,其实这两个类实现了我们所熟知的HttpServletRequest和 HttpServletResponse接口。 |
|
五、高级性能 |
|
1.HttpHandler: |
|
该接口的实现类用于处理HttpContext分发过来的reqeust,不同的实现类的 有不同的处理功能,这里介绍几常用的HttpHandler实现类: | |
ReourceHandler:用于处理静态内容,如以扩展名为.html的文件 | |
SecurityHandler:提供基本的安全验证 |
|
ForwardHandler:转发一个request到另一个url |
|
ServletHandler:用于将request交由具体的Servlet类进行处理 | |
2.当你在看图 1-2 时候会注意到HttpServer和HttpListener,HttpServer与HttpContext,HttpContext与 HttpHandler存在一对多的关系,下面就介绍一下它们之间的这种关系如何通过程序来配置. | |
HttpListener & HttpServer: |
|
HttpListener是所有监听器类的接口,如图中的SocketListener (基于传统的Socket技术)就实现了该接口,Jetty还有其它的实现该接口类,如SocketChannelListener(基于NIO技术)类 等,HttpListener职责主要是在服务器启动后监听相应端口的来自客户端请求并建立连接(图 1-1 中所示用HttpConnection封装连接细节),监听器可在同个IP上开启多个端口为同一个HttpServer 进行监听,所以HttpListener和HttpServer是多对一的关系,如下图: |
|
<图 1-3 > |
|
配置代码: | |
HttpServer server = new HttpServer(); | |
HttpListenrer listener1 = new SocketChanneListener(); | |
Listener1.setPort(8080); | |
HttpListenrer listener1 = new SocketListener(); | |
Listener1.setPort(8443); | |
server.addListener(listener1); | |
server.addListener(listener2); | |
HttpContext & HttpHandler: |
|
HttpContext相当于对应客户端请求的URL或某个虚拟机, 其子类中包含若干个HttpHandler, 当接受到request(请求)时,HttpContext会依次(按某个预定的次序)把request交给这些HttpHandler处理,直到这个 request被标示处理过为止, 需要注意的是这个request可能被多个HttpHandler处理,但只能有一个HttpHandler能标示这个request已被处理过. |
|
一个典型的HttpContext有用于安全处理、静态资源处理及Servlet类的 HttpHandler,如下图: | |
<图 1-4>
|
|
配置代码: | |
HttpContext context = new HttpContext(); | |
context.setContextPath(“/myapp/*”); | |
HttpHandler securitHandler = new SecurityHandler(); | |
HttpHandler resourceHandler = new ResourceHandler(); | |
HttpHandler servletHandler = new ServletHandler(); | |
context.addHandler(securitHandler); | |
context.addHandler(resourceHandler); | |
context.addHandler(servletHandler); | |
HttpServer & HttpContext: | |
一般的HTTP服务器软件可以同时处理多个web application,同样一个HttpServer可以包含多个HttpContext,如下图可以通过同一个端口的监听类来映射多个 HttpContext: | |
<图 1-5 > |
|
配置代码: | |
HttpServer server = new HttpServer(); | |
HttpContext context1 = new HttpContext(); | |
context1.setContextPath(“/app1/*”); | |
HttpContext context2 = new HttpContext(); | |
context2.setContextPath(“/app2/*”); | |
server.addContext(context1); | |
HttpServer & HttpLister & HttpContext: | |
另外Jetty对多网卡(多个IP地址,不同的主机名)的服务器也提供了很好的支持,每个 HttpContext都有自身的HttpServer: |
|
<图 1-6 > |
|
配置代码: | |
HttpServer server1 = new HttpServer(); | |
SocketListener listener1 = new SocketListener(); | |
listener1.setHost(“www.app1.com”);//orListener1.setHost(“www.app2.com”) |
|
listener2.setPort(80); |
|
HttpContext context1 = new HttpContext(); |
|
context1.setContextPath(“/”); |
|
server1.addListener(listener1); | |
server1.addContext(context1); |
|
3.Jetty对高并发的支持 | |
<图 1-8>
|
|
如果多用户请求服务就会涉及到多线程的管理,如图 1-8,Jetty中主要由ThreadPool负责管理多线程,注意其中Pool.PondLife是Pool的一个内部接口, ThreadPool.PoolThread是ThreadPool的一个内部线程类,我们看到Pool.PondLife和Pool存在一个聚集的关 系,实际上Pool对象中存放在是一个个ThreadPool.PoolThread线程对象,当有新用户连接上Server时,ThreadPool就 从Pool中取一个空闲的线程为当前用户连接服务。 | |
六、小结 |
|
本文通过图示简要介绍了Jetty整个体系架构和主要的组件类及服务器的启动执行过程,其 实Jetty 通常被用来做为内嵌的Web Server来使用,一些常见的服务器软件,如Apache Cocoon、JBoss ,JOnAs等都会采用Jetty作为Web解決方案;另外由于Jetty在性能及稳定性要优于同类HTTP Server的原因,Jetty已在国外已很流行,鉴于这一点,本文作者可以预测在不久的将来Jetty同样也会在国内流行开来。 |
转载:http://oss.org.cn/ossdocs/jetty/1.html
Jetty 源码分析的更多相关文章
- flume jetty 进程关系 flume jetty 跨域问题 jetty 源码分析
flume jetty 跨域问题 13481 httpSource的端口进程号 = flume 启动后的进程号 [root@c log]# netstat -atp Active Internet ...
- Jetty源码分析(一)
一.目的 1.了解jetty组成架构: 2.学习jetty启动过程: 3.学习请求访问过程: 4.学习jetty内各模块作用,学习各模块内部代码: 二.jetty版本 本文所学习的jetty版本为:9 ...
- Jetty - Container源码分析
1. 描述 Container提供管理bean的能力. 基于Jetty-9.4.8.v20171121. 1.1 API public interface Container { // 增加一个bea ...
- 《深入理解Spark:核心思想与源码分析》(前言及第1章)
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
- 《深入理解Spark:核心思想与源码分析》一书正式出版上市
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
- 《深入理解Spark:核心思想与源码分析》正式出版上市
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
- Solr5.0源码分析-SolrDispatchFilter
年初,公司开发法律行业的搜索引擎.当时,我作为整个系统的核心成员,选择solr,并在solr根据我们的要求做了相应的二次开发.但是,对solr的还没有进行认真仔细的研究.最近,事情比较清闲,翻翻sol ...
- Solr4.8.0源码分析(4)之Eclipse Solr调试环境搭建
Solr4.8.0源码分析(4)之Eclipse Solr调试环境搭建 由于公司里的Solr调试都是用远程jpda进行的,但是家里只有一台电脑所以不能jpda进行调试,这是因为jpda的端口冲突.所以 ...
- SparkThriftServer 源码分析
目录 版本 起点 客户端--Beeline 服务端 Hive-jdbc TCLIService.Iface客户端请求 流程 SparkThrift 主函数HiveThriftServer2 Thrif ...
随机推荐
- 【linux】centos6.5搭建svn
1.检查是否已安装 rpm -qa subversion 如果要卸载旧版本: yum remove subversion 2.安装 yum install subversion PS:yum inst ...
- 02 - Unit04:笔记本加载功能
@ExceptionHandler 在控制器中统一处理异常. 为了重用异常处理方法,可以将处理方法抽象到父类中,子类共享异常处理方法. 语法: @ExceptionHandler(Exception. ...
- <meta name="viewport" content="width=device-width, initial-scale=1.0">的说明
今天在做适配手机版时,chrome调到手机版,但是还是显示PC端的样式,无法展现出手机端的样式: 开始的时候还以为是chrome版本的问题,最新版本的chrome62.0是有很多变化的,而之前工作中使 ...
- python 下载图片的方法
a='http://wx1.sinaimg.cn/mw600/006HOayNgy1fqjdi2nxohj32pw3o8x6s.jpg' #图片下载地址 ( 这里改成 文件txt地址)w='/U ...
- [Java.web]EL表达式
<%@page import="cn.itcast.domain.Address"%> <%@page import="cn.itcast.domain ...
- ssh登录很慢的问题
1.关闭ssh DNS反向解析 vi /etc/ssh/sshd_config 修改UseDNS no 2.关闭 GSSAPI 的用户认证 vi /etc/ssh/sshd_config 修改GS ...
- 管理Linux服务器的用户和组
管理Linux服务器的用户和组 Linux操作系统是一个多用户多任务的操作系统,允许多个用户同时登录到系统,使用系统资源. 为了使所有用户的工作顺利进行,保护每个用户的文件和进程,规范每个用户的权限, ...
- android studio 3.0.1使用笔记(一)20171231
首先安装JDK1.8.1并设置环境变量JAVA_HOME(C:/JAVA/JDK)及PATH(;%JAVA_HOME%\bin ) 然后安装AS 然后首次AS运行并退出,将GRADLE-4-1.ZIP ...
- python的with用法(参考)
一.With语句是什么? 有一些任务,可能事先需要设置,事后做清理工作.对于这种场景,Python的with语句提供了一种非常方便的处理方式.一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中 ...
- Spring cloud Hystrix的配置属性优先级和详解
Hystrix配置属性详解 Hystrix可以配置属性的有以下类型: Execution:控制HystrixCommand.run() 的如何执行 Fallback: 控制HystrixCommand ...