Jetty的基本架构前端
jetty的主要组件的类图java
整个 Jetty 的核心是围绕着 Server 类来构建,Server 类继承了 Handler,关联了 Connector 和 Container。Container 是管理 Mbean 的容器。nginx
Jetty 的 Server 的扩展主要是实现一个个 Handler 并将 Handler 加到 Server 中,Server 中提供了调用这些 Handler 的访问规则。web
整个 Jetty 的全部组件的生命周期管理是基于观察者模板设计,它和 Tomcat 的管理是相似的。下面是 LifeCycle 的类关系图后端
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 的启动时序图:架构
由于 Jetty 中全部的组件都会继承 LifeCycle,因此 Server 的 start 方法调用就会调用全部已经注册到 Server 的组件,app
Server 启动其它组件的顺序是:负载均衡
首先启动设置到 Server 的 Handler,一般这个 Handler 会有不少子 Handler,这些 Handler 将组成一个 Handler 链。Server 会依次启动这个链上的全部 Handler。
接着会启动注册在 Server 上 JMX 的 Mbean,让 Mbean 也一块儿工做起来。
最后会启动 Connector,打开端口,接受客户端请求,启动逻辑很是简单。
Jetty 做为一个独立的 Servlet 引擎能够独立提供 Web 服务,基于HTTP协议,也能够与其余 Web 应用服务器集成,基于 AJP 协议。
若是前端没有其它 web 服务器,那么 Jetty 应该是基于 HTTP 协议工做。也就是当 Jetty 接收到一个请求时,必需要按照 HTTP 协议解析请求和封装返回的数据。
咱们设置 Jetty 的 Connector 实现类为 org.eclipse.jetty.server.bi.SocketConnector 让 Jetty 以 BIO 的方式工做,Jetty 在启动时将会建立 BIO 的工做环境,它会建立 HttpConnection 类用来解析和封装 HTTP1.1 的协议。
ConnectorEndPoint 类是以 BIO 的处理方式处理链接请求。
ServerSocket 是创建 socket 链接接受和传送数据。
Executor 是处理链接的线程池,它负责处理每个请求队列中任务。acceptorThread 是监听链接请求,一有 socket 链接,它将进入下面的处理流程。
当 socket 被真正执行时,HttpConnection 将被调用,这里定义了如何将请求传递到 servlet 容器里,有如何将请求最终路由到目的 servlet,关于这个细节能够参考《 servlet 工做原理解析》一文。
下图是 Jetty 启动建立创建链接的时序图:
Jetty 建立接受链接环境须要三个步骤:
Accetptor 线程将会为这个请求建立 ConnectorEndPoint。HttpConnection 用来表示这个链接是一个 HTTP 协议的链接,它会建立 HttpParse 类解析 HTTP 协议,而且会建立符合 HTTP 协议的 Request 和 Response 对象。接下去就是将这个线程交给队列线程池去执行了。
一般一个 web 服务站点的后端服务器不是将 Java 的应用服务器直接暴露给服务访问者,而是在应用服务器,如 Jboss 的前面在加一个 web 服务器,如 Apache 或者 nginx,我想这个缘由你们应该很容易理解,如作日志分析、负载均衡、权限控制、防止恶意请求以及静态资源预加载等等。
下图是一般的 web 服务端的架构图:
这种架构下 servlet 引擎就不须要解析和封装返回的 HTTP 协议,由于 HTTP 协议的解析工做已经在 Apache 或 Nginx 服务器上完成了,Jboss 只要基于更加简单的 AJP 协议工做就好了,这样能加快请求的响应速度。
类 Ajp13Parserer 而不是 HttpParser
须要配置 connector 的实现类为 Ajp13SocketConnector
将 SocketConnector 类替换成了 Ajp13SocketConnector
Selector selector = Selector.open(); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking( false ); SelectionKey key = ssc.register( selector, SelectionKey.OP_ACCEPT ); ServerSocketChannel ss = (ServerSocketChannel)key.channel(); SocketChannel sc = ss.accept(); sc.configureBlocking( false ); SelectionKey newKey = sc.register( selector, SelectionKey.OP_READ ); Set selectedKeys = selector.selectedKeys();
后遍历这个观察者观察到事件,取出感兴趣的事件再处理。这里有个最核心的地方就是,咱们不须要为每一个被观察者建立一个线程来监控它随时发生的事件。而是把这些被观察者都注册一个地方统一管理,而后由它把触发的事件统一发送给感兴趣的程序模块。这里的核心是可以统一的管理每一个被观察者的事件,因此咱们就能够把服务端上每一个创建的链接传送和接受数据做为一个事件统一管理,这样就没必要要每一个链接须要一个线程来维护了。
下面是 Jetty 的 NIO 处理时序图:
实际上 Jetty 的工做方式很是简单,当 Jetty 接受到一个请求时,Jetty 就把这个请求交给在 Server 中注册的代理 Handler 去执行,如何执行你注册的 Handler,一样由你去规定,Jetty 要作的就是调用你注册的第一个 Handler 的 handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) 方法,接下去要怎么作,彻底由你决定。
要能接受一个 web 请求访问,首先要建立一个 ContextHandler,以下代码所示:
Server server = new Server(8080); ContextHandler context = new ContextHandler(); context.setContextPath("/"); context.setResourceBase("."); context.setClassLoader(Thread.currentThread().getContextClassLoader()); server.setHandler(context); context.setHandler(new HelloHandler()); server.start(); server.join();
当咱们在浏览器里敲入 http://localhost:8080 时的请求将会代理到 Server 类的 handle 方法,Server 的 handle 的方法将请求代理给 ContextHandler 的 handle 方法,ContextHandler 又调用 HelloHandler 的 handle 方法。这个调用方式是否是和 Servlet 的工做方式相似,在启动以前初始化,而后建立对象后调用 Servlet 的 service 方法。在 Servlet 的 API 中我一般也只实现它的一个包装好的类,在 Jetty 中也是如此,虽然 ContextHandler 也只是一个 Handler,可是这个 Handler 一般是由 Jetty 帮你实现了,咱们通常只要实现一些咱们具体要作的业务逻辑有关的 Handler 就行了,而一些流程性的或某些规范的 Handler,咱们直接用就行了,以下面的关于 Jetty 支持 Servlet 的规范的 Handler 就有多种实现,下面是一个简单的 HTTP 请求的流程。
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。下面是请求这个 Servlet 的时序图:
上图能够看出 Jetty 处理请求的过程就是 Handler 链上 handle 方法的执行过程,在这里须要解释的一点是 ScopeHandler 的处理规则,ServletContextHandler、SessionHandler 和 ServletHandler 都继承了 ScopeHandler,那么这三个类组成一个 Handler 链,它们的执行规则是:ServletContextHandler.handleServletContextHandler.doScope SessionHandler. doScopeServletHandler. doScopeServletContextHandler. doHandleSessionHandler. doHandleServletHandler. doHandle,它这种机制使得咱们能够在 doScope 作一些额外工做。
https://www.ibm.com/developerworks/cn/java/j-lo-jetty/