加入收藏 | 设为首页 | 会员中心 | 我要投稿 西安站长网 (https://www.029zz.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 业界 > 正文

详解Web容器 - Jetty与Tomcat孰强孰弱

发布时间:2019-03-17 07:18:00 所属栏目:业界 来源:博客园
导读:副标题#e# Jetty 基本架构 Jetty目前的是一个比较被看好的 Servlet 引擎,它的架构比较简单,也是一个可扩展性和非常灵活的应用服务器。它有一个基本数据模型,这个数据模型就是 Handler(处理器),所有可以被扩展的组件都可以作为一个 Handler,添加到 Serv

这里需要注意的地方时,很多人认为监听 SelectionKey.OP_ACCEPT 事件就已经是非阻塞方式了,其实 Jetty 仍然是用一个线程来监听客户端的连接请求,当接受到请求后,把这个请求再注册到 Selector 上,然后才是非阻塞方式执行。这个地方还有一个容易引起误解的地方是:认为 Jetty 以 NIO 方式工作只会有一个线程来处理所有的请求,甚至会认为不同用户会在服务端共享一个线程从而会导致基于 ThreadLocal 的程序会出现问题,其实从 Jetty 的源码中能够发现,真正共享一个线程的处理只是在监听不同连接的数据传送事件上,比如有多个连接已经建立,传统方式是当没有数据传输时,线程是阻塞的也就是一直在等待下一个数据的到来,而 NIO 的处理方式是只有一个线程在等待所有连接的数据的到来,而当某个连接数据到来时 Jetty 会把它分配给这个连接对应的处理线程去处理,所以不同连接的处理线程仍然是独立的。

Jetty 的 NIO 处理方式和 Tomcat 的几乎一样,唯一不同的地方是在如何把监听到事件分配给对应的连接的处理方式。从测试效果来看 Jetty 的 NIO 处理方式更加高效。下面是 Jetty 的 NIO 处理时序图:

处理请求

下面看一下 Jetty 是如何处理一个 HTTP 请求的。

实际上 Jetty 的工作方式非常简单,当 Jetty 接受到一个请求时,Jetty 就把这个请求交给在 Server 中注册的代理 Handler 去执行,如何执行你注册的 Handler,同样由你去规定,Jetty 要做的就是调用你注册的第一个 Handler 的 handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) 方法,接下去要怎么做,完全由你决定。

要能接受一个 web 请求访问,首先要创建一个 ContextHandler,,如下代码所示:

  1. Server server = new Server(8080);  
  2.  ContextHandler context = new ContextHandler();  
  3.  context.setContextPath("/");  
  4.  context.setResourceBase(".");  
  5.  context.setClassLoader(Thread.currentThread().getContextClassLoader());  
  6.  server.setHandler(context);  
  7.  context.setHandler(new HelloHandler());  
  8.  server.start();  
  9.  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 请求的流程。

访问一个 Servlet 的代码:

  1. Server server = new Server();  
  2.  Connector connector = new SelectChannelConnector();  
  3.  connector.setPort(8080);  
  4.  server.setConnectors(new Connector[]{ connector });  
  5.  ServletContextHandler root = new  
  6.  ServletContextHandler(null,"/",ServletContextHandler.SESSIONS);  
  7.  server.setHandler(root);  
  8.  root.addServlet(new ServletHolder(new  
  9.  org.eclipse.jetty.embedded.HelloServlet("Hello")),"/");  
  10.  server.start();  
  11.  server.join(); 

创建一个 ServletContextHandler 并给这个 Handler 添加一个 Servlet,这里的 ServletHolder 是 Servlet 的一个装饰类,它十分类似于 Tomcat 中的 StandardWrapper。下面是请求这个 Servlet 的时序图:

图 12. Jetty 处理请求的时序图

上图可以看出 Jetty 处理请求的过程就是 Handler 链上 handle 方法的执行过程,在这里需要解释的一点是 ScopeHandler 的处理规则,ServletContextHandler、SessionHandler 和 ServletHandler 都继承了 ScopeHandler,那么这三个类组成一个 Handler 链,它们的执行规则是:ServletContextHandler.handleServletContextHandler.doScope SessionHandler. doScopeServletHandler. doScopeServletContextHandler. doHandleSessionHandler. doHandleServletHandler. doHandle,它这种机制使得我们可以在 doScope 做一些额外工作。

与 Jboss 集成

(编辑:西安站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读