Jetty 源码分析

一、 总括

你了解Jetty 吗,就像我们所熟知的Tomcat一样, Jetty是一个免费的开放源码的100%纯Java的Http服务器和Servlet容器。

Jetty具备以下特点:

快速高效

。Jetty是最快的Servlet服务器之一

。Jetty可以处理上千个并发连接

小巧嵌入

。Jetty的jar只有600多K

。可动态嵌入到应用程序,适合开发web2.0等应用

应用广泛

。开源项目有Geronimo, JBoss, JOnAS等

。商业项目有IBM Tivoli, Sonic MQ and Cisco SESM等

可到Jetty网站 http://jetty.mortbay.org/jetty/ 查看最新信息

本文将通过对Jetty最新稳定版 Jetty5.1.5RC2 源码的研究,向读者展示Jetty在设计方面使用的不同设计理念, 希望对广大开发者在设计自己的系统时有所帮助。

Jetty按照功能可以分为四个主个主要的部分,HttpServer, HttpContext,HttpHandler,HttpListener,详见如下类图:

Jetty 源码分析

<图 1-1>

二、HttpServer及配置

对于初次接触Jetty的人一定会对上图感到迷惑,其实在Jetty中 HttpServer是一个服务器的核心控制类, 我们可以看到,其它的组件类都是由该类扩展开来,HttpServer的作用就是在一系列的监听器类和处理器类之间搭起了一个桥梁,有效的控制着消息在系统内的传递,如下图:

Jetty 源码分析

<图 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(请求)。

四、运行原理(请参考如下时序图)

Jetty 源码分析

<图 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接口。

Jetty 的详细介绍:请点这里
Jetty 的下载地址:请点这里

推荐阅读:

相关推荐