前言

Context容器是一个Web项目的代表,主要管理Servlet实例,在Tomcat中Servlet实例是以Wrapper出现的。如今问题是怎样才干通过Context容器找到详细的Servlet呢?在解决问题之前。Context容器须要先启动,启动的过程就是载入个类资源文件以及打开子容器以及Pipeline管道的过程。启动Context容器后。就能够处理详细的请求了,详细是通过Request对象,从代码清单4-3的Wrapper wrapper = request.getWrapper()就能够看出来。

那么Context调用invoke方法后又发生什么了呢?详细运行的是org.apache.catalina.core.StandardContextValve的invoke方法。相当于进入了Context管道中,要開始通过管道中一个个闸门了。

StandardContext的处理流程能够用以下的图简化:

代码清单4-3:

/*** Select the appropriate child Wrapper to process this request,* based on the specified request URI.  If no matching Wrapper can* be found, return an appropriate HTTP error.** @param request Request to be processed* @param response Response to be produced** @exception IOException if an input/output error occurred* @exception ServletException if a servlet error occurred*/
@Override
public final void invoke(Request request, Response response)throws IOException, ServletException {// Disallow any direct access to resources under WEB-INF or META-INFMessageBytes requestPathMB = request.getRequestPathMB();if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))|| (requestPathMB.equalsIgnoreCase("/META-INF"))|| (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))|| (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {response.sendError(HttpServletResponse.SC_NOT_FOUND);return;}// Select the Wrapper to be used for this RequestWrapper wrapper = request.getWrapper();if (wrapper == null || wrapper.isUnavailable()) {response.sendError(HttpServletResponse.SC_NOT_FOUND);return;}// Acknowledge the requesttry {response.sendAcknowledgement();} catch (IOException ioe) {container.getLogger().error(sm.getString("standardContextValve.acknowledgeException"), ioe);request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);return;}if (request.isAsyncSupported()) {request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());}wrapper.getPipeline().getFirst().invoke(request, response);
}
  1. 禁止直接訪问WEB-INF或者META-INF文件夹下的资源
  2. 选择详细的Wrapper处理请求
  3. 返回一个确认响应
  4. 调用Wrapper容器的invoke方法,把处理请求交给StandardWrapperValve处理

Wrapper容器
Wrapper容器负责管理一个Servlet,包含Servlet的装载、初始化、资源回收。Wrapper是最底层的容器,其不能在加入子容器了。Wrapper是一个接口。其标准实现类是StandardWrapper,以下是这两个类的结构:


上面的图都仅仅是类的一部分。因为Wrapper与Servlet息息相关。当中的loadServlet方法负责装载Servlet,其源代码例如以下:

代码清单4-4:

/*** Load and initialize an instance of this servlet, if there is not already* at least one initialized instance.  This can be used, for example, to* load servlets that are marked in the deployment descriptor to be loaded* at server startup time.*/
public synchronized Servlet loadServlet() throws ServletException {if (unloading) {throw new ServletException(sm.getString("standardWrapper.unloading", getName()));}// Nothing to do if we already have an instance or an instance poolif (!singleThreadModel && (instance != null))return instance;PrintStream out = System.out;if (swallowOutput) {SystemLogHandler.startCapture();}Servlet servlet;try {long t1=System.currentTimeMillis();// Complain if no servlet class has been specifiedif (servletClass == null) {unavailable(null);throw new ServletException(sm.getString("standardWrapper.notClass", getName()));}InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();try {servlet = (Servlet) instanceManager.newInstance(servletClass);} catch (ClassCastException e) {unavailable(null);// Restore the context ClassLoaderthrow new ServletException(sm.getString("standardWrapper.notServlet", servletClass), e);} catch (Throwable e) {e = ExceptionUtils.unwrapInvocationTargetException(e);ExceptionUtils.handleThrowable(e);unavailable(null);// Added extra log statement for Bugzilla 36630:// http://issues.apache.org/bugzilla/show_bug.cgi?id=36630if(log.isDebugEnabled()) {log.debug(sm.getString("standardWrapper.instantiate", servletClass), e);}// Restore the context ClassLoaderthrow new ServletException(sm.getString("standardWrapper.instantiate", servletClass), e);}if (multipartConfigElement == null) {MultipartConfig annotation =servlet.getClass().getAnnotation(MultipartConfig.class);if (annotation != null) {multipartConfigElement =new MultipartConfigElement(annotation);}}processServletSecurityAnnotation(servlet.getClass());// Special handling for ContainerServlet instancesif ((servlet instanceof ContainerServlet) &&(isContainerProvidedServlet(servletClass) ||((Context) getParent()).getPrivileged() )) {((ContainerServlet) servlet).setWrapper(this);}classLoadTime=(int) (System.currentTimeMillis() -t1);if (servlet instanceof SingleThreadModel) {if (instancePool == null) {instancePool = new Stack<Servlet>();}singleThreadModel = true;}//init servlet instanceinitServlet(servlet);fireContainerEvent("load", this);loadTime=System.currentTimeMillis() -t1;} finally {if (swallowOutput) {String log = SystemLogHandler.stopCapture();if (log != null && log.length() > 0) {if (getServletContext() != null) {getServletContext().log(log);} else {out.println(log);}}}}return servlet;
}

该类主要负责初始化一个Servlet实例,并调用该实例的init方法,然后通知感兴趣的事件监听程序。代码清单4-3中调用了Wrapper的invoke方法,这种方法完毕什么呢?

代码清单4-5:

/*** Invoke the servlet we are managing, respecting the rules regarding* servlet lifecycle and SingleThreadModel support.** @param request Request to be processed* @param response Response to be produced** @exception IOException if an input/output error occurred* @exception ServletException if a servlet error occurred*/
@Override
public final void invoke(Request request, Response response)throws IOException, ServletException {// Initialize local variables we may needboolean unavailable = false;Throwable throwable = null;// This should be a Request attribute...long t1=System.currentTimeMillis();requestCount++;StandardWrapper wrapper = (StandardWrapper) getContainer();Servlet servlet = null;Context context = (Context) wrapper.getParent();// Check for the application being marked unavailableif (!context.getState().isAvailable()) {response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,sm.getString("standardContext.isUnavailable"));unavailable = true;}// Check for the servlet being marked unavailableif (!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;}// Allocate a servlet instance to process this requesttry {if (!unavailable) {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);} catch (Throwable e) {ExceptionUtils.handleThrowable(e);container.getLogger().error(sm.getString("standardWrapper.allocateException",wrapper.getName()), e);throwable = e;exception(request, response, e);servlet = null;}// Identify if the request is Comet related now that the servlet has been allocatedboolean comet = false;if (servlet instanceof CometProcessor && request.getAttribute(Globals.COMET_SUPPORTED_ATTR) == Boolean.TRUE) {comet = true;request.setComet(true);}MessageBytes requestPathMB = request.getRequestPathMB();DispatcherType dispatcherType = DispatcherType.REQUEST;if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC; request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,requestPathMB);// Create the filter chain for this requestApplicationFilterFactory factory =ApplicationFilterFactory.getInstance();ApplicationFilterChain filterChain =factory.createFilterChain(request, wrapper, servlet);// Reset comet flag value after creating the filter chainrequest.setComet(false);// Call the filter chain for this request// NOTE: This also calls the servlet's service() methodtry {if ((servlet != null) && (filterChain != null)) {// Swallow output if neededif (context.getSwallowOutput()) {try {SystemLogHandler.startCapture();if (request.isAsyncDispatching()) {//TODO SERVLET3 - async((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else 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 (request.isAsyncDispatching()) {//TODO SERVLET3 - async((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();} else if (comet) {request.setComet(true);filterChain.doFilterEvent(request.getEvent());} else {filterChain.doFilter(request.getRequest(), response.getResponse());}}}} catch (ClientAbortException e) {throwable = e;exception(request, response, e);} catch (IOException e) {container.getLogger().error(sm.getString("standardWrapper.serviceException", wrapper.getName(),context.getName()), e);throwable = e;exception(request, response, e);} catch (UnavailableException e) {container.getLogger().error(sm.getString("standardWrapper.serviceException", wrapper.getName(),context.getName()), e);//            throwable = e;//            exception(request, response, 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()));}// Do not save exception in 'throwable', because we// do not want to do exception(request, response, e) processing} catch (ServletException e) {Throwable rootCause = StandardWrapper.getRootCause(e);if (!(rootCause instanceof ClientAbortException)) {container.getLogger().error(sm.getString("standardWrapper.serviceExceptionRoot",wrapper.getName(), context.getName(), e.getMessage()),rootCause);}throwable = e;exception(request, response, e);} catch (Throwable e) {ExceptionUtils.handleThrowable(e);container.getLogger().error(sm.getString("standardWrapper.serviceException", wrapper.getName(),context.getName()), e);throwable = e;exception(request, response, e);}// Release the filter chain (if any) for this requestif (filterChain != null) {if (request.isComet()) {// If this is a Comet request, then the same chain will be used for the// processing of all subsequent events.filterChain.reuse();} else {filterChain.release();}}// Deallocate the allocated servlet instancetry {if (servlet != null) {wrapper.deallocate(servlet);}} catch (Throwable e) {ExceptionUtils.handleThrowable(e);container.getLogger().error(sm.getString("standardWrapper.deallocateException",wrapper.getName()), e);if (throwable == null) {throwable = e;exception(request, response, e);}}// If this servlet has been marked permanently unavailable,// unload it and release this instancetry {if ((servlet != null) &&(wrapper.getAvailable() == Long.MAX_VALUE)) {wrapper.unload();}} catch (Throwable e) {ExceptionUtils.handleThrowable(e);container.getLogger().error(sm.getString("standardWrapper.unloadException",wrapper.getName()), e);if (throwable == null) {throwable = e;exception(request, response, e);}}
}
  1. 初始化一些本地变量
  2. 推断当前应用是否可用。就是推断是否确实有这个项目
  3. 分配一个Servlet实例
  4. 为请求创建一个过滤器链
  5. 过滤器过滤请求
  6. 关闭过滤器
  7. 又一次委派原来委派的Servlet实例
  8. 释放资源

这种方法与上面的loadServlet关系例如以下:

能够看出在调用loadServlet的allocate方法的时候调用了StandardWrapperValve的invoke方法,在Wrapper容器获得请求后,通过allocate方法从实例池栈中弹出一个servlet实例来处理这个请求,servlet实例被封装成filterChain对象,紧接着通过一系列的过滤器过滤到达servlet.service()方法。这个过程能够例如以下:

深入理解Tomcat系列之五:Context容器和Wrapper容器相关推荐

  1. 深入理解Tomcat系列之一:系统架构(转)

    前言 Tomcat是Apache基金组织下的开源项目,性质是一个Web服务器.下面这种情况很普遍:在eclipse床架一个web项目并部署到Tomcat中,启动tomcat,在浏览器中输入一个类似ht ...

  2. tomcat lifecyclelistener_大公司程序员带你死磕Tomcat系列(五)——容器

    死磕Tomcat系列(5)--容器 回顾 在死磕Tomcat系列(1)--整体架构中我们简单介绍了容器的概念,并且说了在容器中所有子容器的父接口是Container.在死磕Tomcat系列(2)--E ...

  3. 深入理解Tomcat和Jetty源码之第四篇tomcat系统架构上:容器是如何设计的

    今天来介绍一下Tomcat的容器机制: 1.Tomcat的四种容器 2.容器示意图 3.责任链模式介绍 4.Tomcat如何确定请求是哪个Wrapper处理的 5.Tomcat的Context和ser ...

  4. 深入理解Tomcat和Jetty源码之第二篇servlet规范和servlet容器

    深入理解Tomcat和Jetty源码之第二篇servlet规范和servlet容器 思维导图总览 这篇推送主要讲servlet的规范和什么是servlet容器? 1.先来讲讲servlet规范: 2. ...

  5. PostgreSQL数据库从入门到精通系列之五:深入理解lsn_proc、lsn_commit、lsn、txId、ts_usec

    PostgreSQL数据库从入门到精通系列之五:深入理解lsn_proc.lsn_commit.lsn.txId.ts_usec 一.深入理解lsn_proc 二.深入理解lsn_commit 三.深 ...

  6. Tomcat系列之Java技术详解

    一.概述 1.前言 在前面几篇博客中,我们和大家说了负载均衡器服务器.Web服务器.反向代理服务器.缓存服务器,从这篇博客开始我们和大家说说应用程序服务器,对于上述内容不了解的博友可以去参考一下我们前 ...

  7. 深入理解Spring系列之四:BeanDefinition装载前奏曲

    转载 https://mp.weixin.qq.com/s?__biz=MzI0NjUxNTY5Nw==&mid=2247483835&idx=1&sn=276911368d4 ...

  8. 深入理解 Tomcat(四)Tomcat 类加载器之为何违背双亲委派模型

    这是我们研究Tomcat的第四篇文章,前三篇文章我们搭建了源码框架,了解了tomcat的大致的设计架构, 还写了一个简单的服务器.按照我们最初订的计划,今天,我们要开始研究tomcat的几个主要组件( ...

  9. 【冰极峰教程系列之五】:无hack并支持透明圆角框的全兼容九宫格布局

    原创:冰极峰 转载请注明出处 时间:2009年7月19日 23:33:05 冰极峰教程系列之一:九宫格基本布局 冰极峰教程系列之二:牢不可破的九宫格布局 冰极峰教程系列之三:三层分离的完美九宫格 冰极 ...

最新文章

  1. python元组转字典_python中怎么将元组、字典转化为列表
  2. R语言chorolayer_R语言空间可视化:绘制英国脱欧投票地图
  3. 桂林电子科技大学计算机导论,Welcome to Guilin University of Electronic Technology(桂林电子科技大学)...
  4. 基于matlab的语音信号基本处理系统,基于matlab的语音信号处理及分析
  5. 杭州招聘计算机专业毕业生,毕业季必看!杭州高校毕业生就业情况:这些专业最吃香!这个岗位最缺人!...
  6. 功率谱 幅值谱_语音合成中的Mel谱和MFCC谱无区别
  7. linux主机添加discuz伪静态规则,(总结)Nginx下Discuz 7.2伪静态规则设置
  8. 关闭惠普计算机通电启动注册表,惠普10代cpu电脑装win7卡logo(安装程序正在更新注册表设置)解决方法...
  9. vCenter Server Appliance 所需的端口
  10. 黄聪:Delphi 日期格式问题 - is not a valid date
  11. C++开发工程师的薪资和未来发展
  12. 为驾驶安全护航,基于目标检测模型实现驾驶疲劳检测
  13. [PKUWC2018] Minimax
  14. 爱快软路由在VMware上安装过程分享,基于多网卡的本机+带多机上网,考研计算机网络实战
  15. stm32中如何使用PCA9685控制舵机(详解)
  16. 大长今人物系列:长今心理第二课——申主簿(转载)
  17. Verilog轮询仲裁器设计——Round Robin Arbiter
  18. 苹果App Store程序提交审核指南中文版
  19. 《鬼谷子本经阴符七术》
  20. QTableView根据内容自动调整大小(resizeColumnToContents解决不了的)

热门文章

  1. C++ 虚函数表解析(转)
  2. 《Pro ASP.NET MVC 3 Framework》学习笔记之十四【示例项目SportsStore】
  3. beyond——实验吧
  4. BeanFactory和FactoryBean
  5. BGP链路冗余使用直接接口和回环口分析
  6. ASP.NET中调用Excel的问题
  7. 很WEB很2.0---ThunderBird
  8. 高通收购恩智浦为什么要中国批准?
  9. 一条长为L的绳子,一面靠墙,另外三边组成矩形,问此矩形最大面积能是多少?...
  10. Matlab for Mac 中文路径乱码解决