`
zddava
  • 浏览: 243022 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Tomcat请求处理(五) -- 请求在容器间的流动

阅读更多
请求在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方式以后再详细看。
分享到:
评论

相关推荐

    Tomcat中容器的pipeline机制 - coldridgeValley - 博客园1

    在Tomcat的架构中,Pipeline(管道)机制扮演着至关重要的角色,它使得请求在不同层次的Container(容器)间高效流动。本文将深入探讨Pipeline机制以及与其密切相关的Valve(阀门)组件。 首先,Tomcat中的...

    容器网页终端(websocket-webshell)

    在WebSocket-WebShell的场景中,Tomcat8可能作为WebSocket服务器运行,处理来自客户端的WebSocket连接,并将这些连接转发到Docker容器中的SSH服务。 在项目"websocket-tail-demo-master"中,我们可以预见到一些关键...

    tomcat7.0.42 下部署websocket需要替换的包

    5. **catalina.jar**:这是Tomcat的核心组件,包含了Servlet容器的主要功能。WebSocket的实现是基于Servlet API的扩展,因此更新这个文件可能包括了WebSocket的实现改进。 6. **tomcat-jdbc.jar**:与`tomcat-dbcp....

    java-websocket聊天室代码+Tomcat8_x64地址+JDK7_x64地址

    它创建了一条持久连接,允许数据在服务器和客户端之间自由流动,而无需为每个消息发送单独的HTTP请求。这极大地提高了性能,尤其适用于需要频繁交互的应用,如在线游戏、聊天室或股票报价。 在这个项目中,主要涉及...

    JSP+SQl Server+Tomcat求职招聘网站

    在本应用中,Tomcat作为Web服务器运行JSP页面,并处理HTTP请求。由于其轻量级、易于配置和管理的特点,Tomcat成为了小型到中型企业级应用的首选服务器。 4. **网站功能**: - **用户注册与登录**:求职者和招聘方...

    Tomcat7、Chrome下web socket的一个例子

    例如,使用SSL/TLS加密保护通信安全,通过WebSocket容器(如Tomcat的WebSocket模块)或自定义负载均衡策略处理高并发场景,以及利用WebSocket Session的复制或备份机制提高系统的可用性。 标签“源码”和“工具”...

    毕业论文jsp46基于jsp的网络拼车系统(jsp+servlet+sqlserver).doc

    - 数据流图:描述数据在系统中流动的路径,帮助理解系统的数据处理流程。 5. **详细设计**: - 前台界面采用Java语言设计,提供交互式的用户体验。 - 后台数据库使用MySQL,保证数据的快速访问和处理。 - 通过...

    SpringBoot基于java的网上手机销售管理系统的开发与实现.zip

    在现代商业环境中,高效、便捷的销售管理系统对于企业至关重要,特别是在手机这样的高流动率商品领域。SpringBoot作为一款由Pivotal团队开发的轻量级框架,凭借其简洁的配置、快速的启动时间和集成了大量优秀组件的...

    springmvc websocket 用户挤退登陆

    在IT行业中,WebSocket是一种在客户端和服务器之间建立长连接的协议,它允许双方进行全双工通信,即数据可以双向流动。Spring MVC是Spring框架的一部分,用于构建Web应用程序,而Spring 4.0版本引入了对WebSocket的...

    websocket、catalina和javax.websocket-api-1.0 jar

    WebSocket是一种在客户端和服务器之间建立长连接的协议,它提供了全双工通信,允许数据在两者之间自由流动,而不需要不断地发起新的HTTP请求。WebSocket API是HTML5的一部分,旨在简化实时通信的应用开发。 ...

    火车订票系统

    在这个火车订票系统中,Tomcat接收并处理来自用户的HTTP请求,调用由Struts1框架处理的Action,执行相应的业务逻辑,然后返回动态生成的HTML页面给用户。开发者需要在Tomcat的webapps目录下部署项目的WAR文件,或...

    大学生就业求职网

    在【大学生就业求职网】中,Struts可能负责处理HTTP请求,管理视图和模型之间的通信,确保数据安全地在控制器、业务逻辑层和用户界面之间流动。 另外,项目标签提到了"tomcat",这是一款广泛使用的Java Servlet容器...

    基于Reactjs+Ant Design+Servlet宾馆管理系统.zip

    在具体的实现过程中,开发者首先需要配置Servlet容器,如Tomcat,然后编写Servlet类,处理HTTP请求。同时,为了实现数据持久化,可能还需要集成MySQL数据库,并使用JDBC或ORM框架(如Hibernate)来操作数据库。在...

    HTML5+WebSocket实例

    而WebSocket一旦建立连接,就能保持开放,允许数据在服务器和浏览器之间自由流动,无需反复发送请求。 在给定的压缩包文件中,包含三个实例,分别展示了WebSocket的不同应用场景: 1. **Tomcat7自带实例**:Tomcat...

    软件技术公司面试题,可以查看

    而**Servlet**更侧重于业务逻辑处理,主要负责数据处理和控制流程。 - JSP编译成Servlet执行,因此JSP本质上是一种简化版的Servlet。 - **联系**: - 在MVC模式中,通常Servlet作为控制器(Controller),JSP作为...

    JAVA POST与GET数据传递时中文乱码问题解决方法

    因为默认情况下,Servlet容器可能使用不同的字符集(如ISO-8859-1)来解析请求参数,所以需要显式设置为UTF-8,以确保中文字符正确解析。 示例代码: ```jsp *" pageEncoding="UTF-8"%&gt; ("UTF-8"); String zh_...

    基于ssm框架的校园疫情管理系统的设计与实现论文-基于ssm框架的校园疫情管理系统的设计与实现-论文-java-文档-ssm

    系统架构采用了B/S模式和MVC设计模式,前端页面使用了HTML、CSS、JavaScript等技术,后端则利用Spring框架进行业务逻辑处理,SpringMVC作为控制器接收并处理请求,MyBatis作为持久层框架负责数据的存取操作。...

Global site tag (gtag.js) - Google Analytics