请求在Tomcat中传到了CoyoteAdapter的#service()方法中后,就要准备进入Pipeline了,如#service()方法中的这句所示:
connector.getContainer().getPipeline().getFirst().invoke(request, response);
这里的Container是Engine,然后得到它的Pipeline对象,然后得到他的第一个Valve,如果没有配置的话第一个Valve就是Basic的了,这里就是org.apache.catalina.core.StandardEngineValve,最后调用了它的#invoke()方法,源代码如下所示:
public final void invoke(Request request, Response response) throws IOException, ServletException { // 获得Host对象 Host host = request.getHost(); if (host == null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, sm.getString( "standardEngine.noHost", request.getServerName())); return; } // 将请求传递给Host host.getPipeline().getFirst().invoke(request, response); }
这个Valve并没做什么实质性的东西,只是将请求继续传递,当然可以定义自己的Valve实现一些特殊的行为。
还是来继续请求的处理过程,和上边Engine的情况类似,请求这次到了org.apache.catalina.core.StandardHostValve的#invoke()方法,源代码如下所示:
public final void invoke(Request request, Response response) throws IOException, ServletException { // 获得Context对象 Context context = request.getContext(); if (context == null) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm .getString("standardHost.noContext")); return; } // 如果没有设置Loader,那么设置为context自己的ClassLoader if (context.getLoader() != null) { Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader()); } // 将请求通过Pipeline给Context context.getPipeline().getFirst().invoke(request, response); if (Globals.STRICT_SERVLET_COMPLIANCE) { request.getSession(false); } // 处理错误页 response.setSuspended(false); Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR); if (t != null) { throwable(request, response, t); } else { status(request, response); } // 恢复ClassLoader Thread.currentThread().setContextClassLoader(StandardHostValve.class.getClassLoader()); }
不出意外的,请求下边就到了org.apache.catalina.core.StandardContextValve,源代码如下:
public final void invoke(Request request, Response response) throws IOException, ServletException { // 不允许请求访问META-INF和WEB-INF文件夹下的内容。 MessageBytes requestPathMB = request.getRequestPathMB(); if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/META-INF")) || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { notFound(response); return; } // 如果系统正在重新载入中,那么暂停请求。 boolean reloaded = false; while (context.getPaused()) { reloaded = true; try { Thread.sleep(1000); } catch (InterruptedException e) { ; } } // 如果正在重载,停止老的WebappClassLoader并创建一个新的 if (reloaded && context.getLoader() != null && context.getLoader().getClassLoader() != null) { Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader()); } // 获得Wrapper对象 Wrapper wrapper = request.getWrapper(); if (wrapper == null) { notFound(response); return; } else if (wrapper.isUnavailable()) { wrapper = (Wrapper) container.findChild(wrapper.getName()); if (wrapper == null) { notFound(response); return; } } // 获得Listener列表 Object instances[] = context.getApplicationEventListeners(); ServletRequestEvent event = null; if ((instances != null) && (instances.length > 0)) { event = new ServletRequestEvent(((StandardContext) container).getServletContext(), request.getRequest()); for (int i = 0; i < instances.length; i++) { if (instances[i] == null) continue; if (!(instances[i] instanceof ServletRequestListener)) continue; ServletRequestListener listener = (ServletRequestListener) instances[i]; try { // 调用请求初始化事件 listener.requestInitialized(event); } catch (Throwable t) { container.getLogger().error( sm.getString("standardContext.requestListener.requestInit", instances[i].getClass().getName()), t); ServletRequest sreq = request.getRequest(); sreq.setAttribute(Globals.EXCEPTION_ATTR, t); return; } } } // 调用Wrapper的Valve wrapper.getPipeline().getFirst().invoke(request, response); if ((instances != null) && (instances.length > 0)) { for (int i = 0; i < instances.length; i++) { if (instances[i] == null) continue; if (!(instances[i] instanceof ServletRequestListener)) continue; ServletRequestListener listener = (ServletRequestListener) instances[i]; try { // 调用请求结束事件 listener.requestDestroyed(event); } catch (Throwable t) { container.getLogger().error( sm.getString("standardContext.requestListener.requestDestroy", instances[i].getClass().getName()), t); ServletRequest sreq = request.getRequest(); sreq.setAttribute(Globals.EXCEPTION_ATTR, t); } } } }
这个Valve重要的是包括了对Listener的调用,最后来看一下Wrapper的Valve调用(org.apache.catalina.core.StandardWrapperValve)。
public final void invoke(Request request, Response response) throws IOException, ServletException { boolean unavailable = false; Throwable throwable = null; long t1 = System.currentTimeMillis(); requestCount++; // 获得Wrapper所关联的对象 StandardWrapper wrapper = (StandardWrapper) getContainer(); // Servlet对象 Servlet servlet = null; // 获得Context对象 Context context = (Context) wrapper.getParent(); if (!context.getAvailable()) { response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm .getString("standardContext.isUnavailable")); unavailable = true; } if (!unavailable && wrapper.isUnavailable()) { container.getLogger().info( sm.getString("standardWrapper.isUnavailable", wrapper.getName())); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString( "standardWrapper.isUnavailable", wrapper.getName())); } else if (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString( "standardWrapper.notFound", wrapper.getName())); } unavailable = true; } try { if (!unavailable) { // 分配一个Servelt实例 servlet = wrapper.allocate(); } } catch (UnavailableException e) { container.getLogger().error( sm.getString("standardWrapper.allocateException", wrapper.getName()), e); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString( "standardWrapper.isUnavailable", wrapper.getName())); } else if (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString( "standardWrapper.notFound", wrapper.getName())); } } catch (ServletException e) { container.getLogger().error( sm.getString("standardWrapper.allocateException", wrapper.getName()), StandardWrapper.getRootCause(e)); throwable = e; exception(request, response, e); servlet = null; } catch (Throwable e) { container.getLogger().error( sm.getString("standardWrapper.allocateException", wrapper.getName()), e); throwable = e; exception(request, response, e); servlet = null; } boolean comet = false; if (servlet instanceof CometProcessor && request.getAttribute("org.apache.tomcat.comet.support") == Boolean.TRUE) { comet = true; request.setComet(true); } // 告知Request已经收到 try { response.sendAcknowledgement(); } catch (IOException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); container.getLogger().warn( sm.getString("standardWrapper.acknowledgeException", wrapper.getName()), e); throwable = e; exception(request, response, e); } catch (Throwable e) { container.getLogger().error( sm.getString("standardWrapper.acknowledgeException", wrapper.getName()), e); throwable = e; exception(request, response, e); servlet = null; } MessageBytes requestPathMB = null; if (request != null) { requestPathMB = request.getRequestPathMB(); } request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, ApplicationFilterFactory.REQUEST_INTEGER); request.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, requestPathMB); // 创建FilterChain ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet); request.setComet(false); try { // web.xml中的<jsp-file>标签 String jspFile = wrapper.getJspFile(); if (jspFile != null) request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); else request.removeAttribute(Globals.JSP_FILE_ATTR); // 调用Filter if ((servlet != null) && (filterChain != null)) { if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); if (comet) { filterChain.doFilterEvent(request.getEvent()); request.setComet(true); } else { filterChain.doFilter(request.getRequest(), response.getResponse()); } } finally { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { context.getLogger().info(log); } } } else { if (comet) { request.setComet(true); filterChain.doFilterEvent(request.getEvent()); } else { filterChain.doFilter(request.getRequest(), response.getResponse()); } } } request.removeAttribute(Globals.JSP_FILE_ATTR); } catch (ClientAbortException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); throwable = e; exception(request, response, e); } catch (IOException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); container.getLogger().error( sm.getString("standardWrapper.serviceException", wrapper.getName()), e); throwable = e; exception(request, response, e); } catch (UnavailableException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); container.getLogger().error( sm.getString("standardWrapper.serviceException", wrapper.getName()), e); wrapper.unavailable(e); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString( "standardWrapper.isUnavailable", wrapper.getName())); } else if (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString( "standardWrapper.notFound", wrapper.getName())); } } catch (ServletException e) { request.removeAttribute(Globals.JSP_FILE_ATTR); Throwable rootCause = StandardWrapper.getRootCause(e); if (!(rootCause instanceof ClientAbortException)) { container.getLogger().error( sm.getString("standardWrapper.serviceException", wrapper.getName()), rootCause); } throwable = e; exception(request, response, e); } catch (Throwable e) { request.removeAttribute(Globals.JSP_FILE_ATTR); container.getLogger().error( sm.getString("standardWrapper.serviceException", wrapper.getName()), e); throwable = e; exception(request, response, e); } if (filterChain != null) { if (request.isComet()) { filterChain.reuse(); } else { filterChain.release(); } } // 释放Servlet对象 try { if (servlet != null) { wrapper.deallocate(servlet); } } catch (Throwable e) { container.getLogger().error( sm.getString("standardWrapper.deallocateException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, e); } } try { if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) { wrapper.unload(); } } catch (Throwable e) { container.getLogger().error( sm.getString("standardWrapper.unloadException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, e); } } long t2 = System.currentTimeMillis(); long time = t2 - t1; processingTime += time; if (time > maxTime) maxTime = time; if (time < minTime) minTime = time; }
这段代码的关键点是Servlet实例的构建(servlet = wrapper.allocate();)和Filter Chain的调用(filterChain.doFilter(request.getRequest(), response.getResponse());),具体的还要进入方法内部去仔细看一下。comet方式以后再详细看。
发表评论
-
出现java.lang.UnsupportedClassVersionError 错误的原因
2010-08-16 23:11 867出现java.lang.UnsupportedClassVer ... -
Tomcat请求处理(七) - Servlet实例的调用
2009-05-07 11:36 1125Tomcat请求处理中Servlet实例的调用是和Filter ... -
请求在Tomcat中传到了CoyoteAdapter的#service()方法中后,就要准备进入Pi
2009-05-07 11:35 1797首先,来看一下Servlet的载入过程。 具体是在org.ap ... -
Tomcat请求处理(四) -- Request, Response, 和Pipeline
2009-05-07 11:33 12811. Request和Response 当处理请求的时候,To ... -
Tomcat请求处理(三) -- coyote请求处理
2009-05-07 11:32 1319在上一篇文章文章中,Tomcat的请求处理到了JIoEndpo ... -
Tomcat请求处理(二) -- 请求处理框架
2009-05-07 11:30 983书接上文。 当Tomcat的Acceptor监听到有请求到来时 ... -
Tomcat请求处理(一) -- 服务器端口监听
2009-05-07 11:29 1393其实tomcat在哪个类中监听请求的代码很容易找到: 在org ... -
Tomcat启动部分源代码分析(五) -- 应用程序加载
2009-05-07 11:28 1194前面所叙述的tomcat启动 ... -
Tomcat启动部分源代码分析(四) -- 开启容器
2009-05-07 11:27 1199四. 开启容器 最后是Bootstrap#start()方法的 ... -
Tomcat启动部分源代码分析(三) -- 载入
2009-05-07 11:23 1188二. 载入 2. Bootstrap的#Bootstrap#l ... -
Tomcat启动部分源代码分析(二) -- 初始化
2009-05-07 11:20 1092二. 初始化 1. 首先是Bootstrap的#init()操 ... -
Tomcat启动部分源代码分析(一) -- 概览
2009-05-07 11:17 1426一. 概览 本文所涉及的Tomcat为6.0版本。 Tomca ... -
Tomcat的Session管理(二) - Session后台处理
2009-05-07 10:10 968Tomcat会开启一个后台线程每隔一段时间检查Session的 ... -
Tomcat的Session管理(一) - Session的生成
2009-05-07 10:02 1490Session对象的创建一般是源于这样的一条语句: Sessi ...
相关推荐
在Tomcat的架构中,Pipeline(管道)机制扮演着至关重要的角色,它使得请求在不同层次的Container(容器)间高效流动。本文将深入探讨Pipeline机制以及与其密切相关的Valve(阀门)组件。 首先,Tomcat中的...
在WebSocket-WebShell的场景中,Tomcat8可能作为WebSocket服务器运行,处理来自客户端的WebSocket连接,并将这些连接转发到Docker容器中的SSH服务。 在项目"websocket-tail-demo-master"中,我们可以预见到一些关键...
5. **catalina.jar**:这是Tomcat的核心组件,包含了Servlet容器的主要功能。WebSocket的实现是基于Servlet API的扩展,因此更新这个文件可能包括了WebSocket的实现改进。 6. **tomcat-jdbc.jar**:与`tomcat-dbcp....
它创建了一条持久连接,允许数据在服务器和客户端之间自由流动,而无需为每个消息发送单独的HTTP请求。这极大地提高了性能,尤其适用于需要频繁交互的应用,如在线游戏、聊天室或股票报价。 在这个项目中,主要涉及...
在本应用中,Tomcat作为Web服务器运行JSP页面,并处理HTTP请求。由于其轻量级、易于配置和管理的特点,Tomcat成为了小型到中型企业级应用的首选服务器。 4. **网站功能**: - **用户注册与登录**:求职者和招聘方...
例如,使用SSL/TLS加密保护通信安全,通过WebSocket容器(如Tomcat的WebSocket模块)或自定义负载均衡策略处理高并发场景,以及利用WebSocket Session的复制或备份机制提高系统的可用性。 标签“源码”和“工具”...
- 数据流图:描述数据在系统中流动的路径,帮助理解系统的数据处理流程。 5. **详细设计**: - 前台界面采用Java语言设计,提供交互式的用户体验。 - 后台数据库使用MySQL,保证数据的快速访问和处理。 - 通过...
在现代商业环境中,高效、便捷的销售管理系统对于企业至关重要,特别是在手机这样的高流动率商品领域。SpringBoot作为一款由Pivotal团队开发的轻量级框架,凭借其简洁的配置、快速的启动时间和集成了大量优秀组件的...
在IT行业中,WebSocket是一种在客户端和服务器之间建立长连接的协议,它允许双方进行全双工通信,即数据可以双向流动。Spring MVC是Spring框架的一部分,用于构建Web应用程序,而Spring 4.0版本引入了对WebSocket的...
WebSocket是一种在客户端和服务器之间建立长连接的协议,它提供了全双工通信,允许数据在两者之间自由流动,而不需要不断地发起新的HTTP请求。WebSocket API是HTML5的一部分,旨在简化实时通信的应用开发。 ...
在这个火车订票系统中,Tomcat接收并处理来自用户的HTTP请求,调用由Struts1框架处理的Action,执行相应的业务逻辑,然后返回动态生成的HTML页面给用户。开发者需要在Tomcat的webapps目录下部署项目的WAR文件,或...
在【大学生就业求职网】中,Struts可能负责处理HTTP请求,管理视图和模型之间的通信,确保数据安全地在控制器、业务逻辑层和用户界面之间流动。 另外,项目标签提到了"tomcat",这是一款广泛使用的Java Servlet容器...
在具体的实现过程中,开发者首先需要配置Servlet容器,如Tomcat,然后编写Servlet类,处理HTTP请求。同时,为了实现数据持久化,可能还需要集成MySQL数据库,并使用JDBC或ORM框架(如Hibernate)来操作数据库。在...
而WebSocket一旦建立连接,就能保持开放,允许数据在服务器和浏览器之间自由流动,无需反复发送请求。 在给定的压缩包文件中,包含三个实例,分别展示了WebSocket的不同应用场景: 1. **Tomcat7自带实例**:Tomcat...
而**Servlet**更侧重于业务逻辑处理,主要负责数据处理和控制流程。 - JSP编译成Servlet执行,因此JSP本质上是一种简化版的Servlet。 - **联系**: - 在MVC模式中,通常Servlet作为控制器(Controller),JSP作为...
因为默认情况下,Servlet容器可能使用不同的字符集(如ISO-8859-1)来解析请求参数,所以需要显式设置为UTF-8,以确保中文字符正确解析。 示例代码: ```jsp *" pageEncoding="UTF-8"%> ("UTF-8"); String zh_...
系统架构采用了B/S模式和MVC设计模式,前端页面使用了HTML、CSS、JavaScript等技术,后端则利用Spring框架进行业务逻辑处理,SpringMVC作为控制器接收并处理请求,MyBatis作为持久层框架负责数据的存取操作。...