建立一个ServletContextServer类,用来初始化web应用程序的Context,而且指定Servlet和Servlet匹配的url。这里指定了两个Servlet,分别是HelloServlet和GoodbyeServlet,并分别对应/hello/*和/goodbye/*。前端
public class ServletContextServer { public static void main(String[] args) throws Exception { Server server = new Server(8080); ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); server.setHandler(context); // http://localhost:8080/hello context.addServlet(new ServletHolder(new HelloServlet()), "/hello"); // http://localhost:8080/hello/kongxx context.addServlet(new ServletHolder(new HelloServlet("Hello Kongxx!")), "/hello/kongxx"); // http://localhost:8080/goodbye context.addServlet(new ServletHolder(new GoodbyeServlet()), "/goodbye"); // http://localhost:8080/goodbye/kongxx context.addServlet(new ServletHolder(new GoodbyeServlet("Goodbye kongxx!")), "/goodbye/kongxx"); server.start(); server.join(); } }
也能够建立两个Context,分别绑定到"/hello"和"/goodbye"nginx
public class MultiContextServer { public static void main(String[] args) throws Exception { Server server = new Server(8080); // http://localhost:8080/hello/kongxx ServletContextHandler context1 = new ServletContextHandler(ServletContextHandler.SESSIONS); context1.setContextPath("/hello"); context1.setResourceBase("."); context1.setClassLoader(Thread.currentThread().getContextClassLoader()); context1.addServlet(new ServletHolder(new HelloServlet("Hello Kongxx!")), "/kongxx"); // http://localhost:8080/goodbye/kongxx ServletContextHandler context2 = new ServletContextHandler(ServletContextHandler.SESSIONS); context2.setContextPath("/goodbye"); context2.setResourceBase("."); context2.setClassLoader(Thread.currentThread().getContextClassLoader()); context2.addServlet(new ServletHolder(new GoodbyeServlet("Goodbye kongxx!")), "/kongxx");
ContextHandlerCollection contexts = new ContextHandlerCollection(); contexts.setHandlers(new Handler[] { context1, context2 }); server.setHandler(contexts); server.start(); server.join(); } }
Jetty 是一个Servlet 引擎,它的架构比较简单,也是一个可扩展性和很是灵活的应用服务器,它有一个基本数据模型,这个数据模型就是 Handler,全部能够被扩展的组件均可以做为一个 Handler,添加到 Server 中,Jetty 就是帮你管理这些 Handler。 web
整个 Jetty 的核心组件由 Server 和 Connector 两个组件构成,整个 Server 组件是基于 Handler 容器工做的,Jetty 中另一个比不可少的组件是 Connector,它负责接受客户端的链接请求,并将请求分配给一个处理队列去执行。Jetty 中还有一些无关紧要的组件,咱们能够在它上作扩展。如 JMX,咱们能够定义一些 Mbean 把它加到 Server 中,当 Server 启动的时候,这些 Bean 就会一块儿工做。算法
整个 Jetty 的核心是围绕着 Server 类来构建,Server 类继承了 Handler,关联了 Connector 和 Container。Container 是管理 Mbean 的容器。Jetty 的 Server 的扩展主要是实现一个个 Handler 并将 Handler 加到 Server 中,Server 中提供了调用这些 Handler 的访问规则。整个 Jetty 的全部组件的生命周期管理是基于观察者模板设计,实现LifeCycle。设计模式
Jetty 主要是基于 Handler 来设计的,Handler 的体系结构影响着整个 Jetty 的方方面面。下面总结了一下 Handler 的种类及做用:服务器
Jetty 主要提供了两种 Handler 类型,一种是 HandlerWrapper,它能够将一个 Handler 委托给另一个类去执行,如咱们要将一个 Handler 加到 Jetty 中,那么就必须将这个 Handler 委托给 Server 去调用。配合 ScopeHandler 类咱们能够拦截 Handler 的执行,在调用 Handler 以前或以后,能够作一些另外的事情,相似于 Tomcat 中的 Valve;另一个 Handler 类型是 HandlerCollection,这个 Handler 类能够将多个 Handler 组装在一块儿,构成一个 Handler 链,方便咱们作扩展。 架构
Jetty 的入口是 Server 类,Server 类启动完成了,就表明 Jetty 能为你提供服务了。它到底能提供哪些服务,就要看 Server 类启动时都调用了其它组件的 start 方法。从 Jetty 的配置文件咱们能够发现,配置 Jetty 的过程就是将那些类配置到 Server 的过程。下面是 Jetty 的启动时序图:app
由于 Jetty 中全部的组件都会继承 LifeCycle,因此 Server 的 start 方法调用就会调用全部已经注册到 Server 的组件,Server 启动其它组件的顺序是:首先启动设置到 Server 的 Handler,一般这个 Handler 会有不少子 Handler,这些 Handler 将组成一个 Handler 链。Server 会依次启动这个链上的全部 Handler。接着会启动注册在 Server 上 JMX 的 Mbean,让 Mbean 也一块儿工做起来,最后会启动 Connector,打开端口,接受客户端请求,启动逻辑很是简单。eclipse
Jetty 做为一个独立的 Servlet 引擎能够独立提供 Web 服务,可是它也能够与其余 Web 应用服务器集成,因此它能够提供基于两种协议工做,一个是 HTTP,一个是 AJP 协议。若是将 Jetty 集成到 Jboss 或者 Apache,那么就可让 Jetty 基于 AJP 模式工做。下面分别介绍 Jetty 如何基于这两种协议工做,而且它们如何创建链接和接受请求的。socket
若是前端没有其它 web 服务器,那么 Jetty 应该是基于 HTTP 协议工做。也就是当 Jetty 接收到一个请求时,必需要按照 HTTP 协议解析请求和封装返回的数据。若是 Jboss 的前面在加一个 web 服务器,如 Apache 或者 nginx,这种架构下 servlet 引擎就不须要解析和封装返回的 HTTP 协议,由于 HTTP 协议的解析工做已经在 Apache 或 Nginx 服务器上完成了,Jboss 只要基于更加简单的 AJP 协议工做就好了。
咱们设置 Jetty 的 Connector 实现类为 org.eclipse.jetty.server.bi.SocketConnector 让 Jetty 以 BIO 的方式工做(org.mortbay.jetty.nio.SelectChannelConnector),Jetty 在启动时将会建立 BIO 的工做环境,它会建立 HttpConnection 类用来解析和封装 HTTP1.1 的协议,ConnectorEndPoint 类是以 BIO 的处理方式处理链接请求,ServerSocket 是创建 socket 链接接受和传送数据,Executor 是处理链接的线程池,它负责处理每个请求队列中任务。acceptorThread 是监听链接请求,一有 socket 链接,它将进入下面的处理流程。当 socket 被真正执行时,HttpConnection 将被调用,这里定义了如何将请求传递到 servlet 容器里,又如何将请求最终路由到目的 servlet(相似servlet的request)。
Jetty 建立接受链接环境须要三个步骤:
当创建链接的环境已经准备好了,就能够接受 HTTP 请求了,Accetptor 线程将会为这个请求建立 ConnectorEndPoint。HttpConnection 用来表示这个链接是一个 HTTP 协议的链接,它会建立 HttpParse 类解析 HTTP 协议,而且会建立符合 HTTP 协议的 Request 和 Response 对象。接下去就是将这个线程交给队列线程池去执行了。
实际上在 AJP 处理请求相比较 HTTP 时惟一的不一样就是在读取到 socket 数据包时,如何来转换这个数据包,是按照 HTTP 协议的包格式来解析就是 HttpParser,按照 AJP 协议来解析就是 Ajp13Parserer。封装返回的数据也是如此。让 Jetty 工做在 AJP 协议下,须要配置 connector 的实现类为 Ajp13SocketConnector,这个类继承了 SocketConnector 类,覆盖了父类的 newConnection 方法,为的是建立 Ajp13Connection 对象而不是 HttpConnection。
实际上 Jetty 的工做方式很是简单,当 Jetty 接受到一个请求时,Jetty 就把这个请求交给在 Server 中注册的代理 Handler 去执行,如何执行你注册的 Handler一样由你去规定,Jetty 要作的就是调用你注册的第一个 Handler 的 handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) 方法,接下去要怎么作,彻底由你决定。
访问一个 Servlet 的代码:
Server server = new Server(); Connector connector = new SelectChannelConnector(); connector.setPort(8080); server.setConnectors(new Connector[]{ connector }); ServletContextHandler root = new ServletContextHandler(null,"/",ServletContextHandler.SESSIONS); server.setHandler(root); root.addServlet(new ServletHolder(new org.eclipse.jetty.embedded.HelloServlet("Hello")),"/"); server.start(); server.join();
建立一个 ServletContextHandler 并给这个 Handler 添加一个 Servlet,这里的 ServletHolder 是 Servlet 的一个装饰类,它十分相似于 Tomcat 中的 StandardWrapper。
上图能够看出 Jetty 处理请求的过程就是 Handler 链上 handle 方法的执行过程,在这里须要解释的一点是 ScopeHandler 的处理规则,ServletContextHandler、SessionHandler 和 ServletHandler 都继承了 ScopeHandler,那么这三个类组成一个 Handler 链,它们的执行规则是:ServletContextHandler.handle->ServletContextHandler.doScope ->SessionHandler. doScope->ServletHandler. doScope->ServletContextHandler. doHandle->SessionHandler. doHandle->ServletHandler. doHandle,它这种机制使得咱们能够在 doScope 作一些额外工做。
架构比较:
Jetty 的架构从前面的分析可知,它的全部组件都是基于 Handler 来实现,固然它也支持 JMX。可是主要的功能扩展均可以用 Handler 来实现。能够说 Jetty 是面向 Handler 的架构,就像 Spring 是面向 Bean 的架构,iBATIS 是面向 statement 同样,而 Tomcat 是以多级容器构建起来的,它们的架构设计必然都有一个“元神”,全部以这个“元神“构建的其它组件都是肉身。
Jetty从设计模板角度来看 Handler 的设计实际上就是一个责任链模式,接口类 HandlerCollection 能够帮助开发者构建一个链,而另外一个接口类 ScopeHandler 能够帮助你控制这个链的访问顺序。另一个用到的设计模板就是观察者模式,用这个设计模式控制了整个 Jetty 的生命周期,只要继承了 LifeCycle 接口,你的对象就能够交给 Jetty 来统一管理了。因此扩展 Jetty 很是简单,也很容易让人理解,总体架构上的简单也带来了无比的好处,Jetty 能够很容易被扩展和裁剪。
Tomcat 要臃肿不少,Tomcat 的总体设计上很复杂,前面说了 Tomcat 的核心是它的容器的设计,从 Server 到 Service 再到 engine 等 container 容器。做为一个应用服务器这样设计无口厚非,容器的分层设计也是为了更好的扩展,这是这种扩展的方式是将应用服务器的内部结构暴露给外部使用者,使得若是想扩展 Tomcat,开发人员必需要首先了解 Tomcat 的总体设计结构,而后才能知道如何按照它的规范来作扩展。这样无形就增长了对 Tomcat 的学习成本。不只仅是容器,实际上 Tomcat 也有基于责任链的设计方式,像串联 Pipeline 的 Vavle 设计也是与 Jetty 的 Handler 相似的方式。要本身实现一个 Vavle 与写一个 Handler 的难度不相上下。表面上看,Tomcat 的功能要比 Jetty 强大,由于 Tomcat 已经帮你作了不少工做了,而 Jetty 只告诉,你能怎么作,如何作,有你去实现。
打个比方,就像小孩子学数学,Tomcat 告诉你 1+1=2,1+2=3,2+2=4 这个结果,而后你能够根据这个方式得出 1+1+2=4,你要计算其它数必须根据它给你的公式才能计算,而 Jetty 是告诉你加减乘除的算法规则,而后你就能够根据这个规则本身作运算了。因此你一旦掌握了 Jetty,Jetty 将变得异常强大。
性能比较:
单纯比较 Tomcat 与 Jetty 的性能意义不是很大,只能说在某种使用场景下,它表现的各有差别。由于它们面向的使用场景不尽相同。从架构上来看 Tomcat 在处理少数很是繁忙的链接上更有优点,也就是说链接的生命周期若是短的话,Tomcat 的整体性能更高。而 Jetty 恰好相反,Jetty 能够同时处理大量链接并且能够长时间保持这些链接。例如像一些 web 聊天应用很是适合用 Jetty 作服务器,像淘宝的 web 旺旺就是用 Jetty 做为 Servlet 引擎。
另外因为 Jetty 的架构很是简单,做为服务器它能够按需加载组件,这样不须要的组件能够去掉,这样无形能够减小服务器自己的内存开销,处理一次请求也是能够减小产生的临时对象,这样性能也会提升。另外 Jetty 默认使用的是 NIO 技术在处理 I/O 请求上更占优点,Tomcat 默认使用的是 BIO,在处理静态资源时,Tomcat 的性能不如 Jetty。
特性比较:
做为一个标准的 Servlet 引擎,它们都支持标准的 Servlet 规范,还有 Java EE 的规范也都支持,因为 Tomcat 的使用的更加普遍,它对这些支持的更加全面一些,有不少特性 Tomcat 都直接集成进来了。可是 Jetty 的应变动加快速,这一方面是由于 Jetty 的开发社区更加活跃,另外一方面也是由于 Jetty 的修改更加简单,它只要把相应的组件替换就行了,而 Tomcat 的总体结构上要复杂不少,修改功能比较缓慢。因此 Tomcat 对最新的 Servlet 规范的支持老是要比人们预期的要晚。