出处:http://gearever.iteye.com
Tomcat提供了engine,host,context及wrapper四种容器。在总体结构中已经阐述了他们之间的包含关系。这四种容器继承了一个容器基类,因此可以定制化。当然,tomcat也提供了标准实现。
- Engine:org.apache.catalina.core.StandardEngine
- Host: org.apache.catalina.core.StandardHost
- Context:org.apache.catalina.core.StandardContext
- Wrapper:org.apache.catalina.core.StandardWrapper
所谓容器,就是说它承载了若干逻辑单元及运行时数据。好比,整个酒店是一个容器,它包含了各个楼层等设施;每个楼层也是容器,它包含了各个房间;每个房间也是容器,它包含了各种家电等等。
首先来看一下容器类的类结构。
基类ContainerBase
ContainerBase是个abstract基类。其类路径为:
org.apache.catalina.core.ContainerBase
这里只列出一些比较核心功能的组件及方法。需要注意的是,类中的方法及属性很多,限于篇幅不全部列出来了。
Enigne
Engine是最顶层的容器,它是host容器的组合。其标准实现类为:
org.apache.catalina.core.StandardEngine
看一下StandardEngine的主要逻辑单元概念图。
从图中可以看出,engine有四大组件:
- Cluster: 实现tomcat集群,例如session共享等功能,通过配置server.xml可以实现,对其包含的所有host里的应用有效,该模块是可选的。其实现方式是基于pipeline+valve模式的,有时间会专门整理一个pipeline+valve模式应用系列;
- Realm:实现用户权限管理模块,例如用户登录,访问控制等,通过通过配置server.xml可以实现,对其包含的所有host里的应用有效,该模块是可选的;
- Pipeline:这里简单介绍下,之后会有专门文档说明。每个容器对象都有一个pipeline,它不是通过server.xml配置产生的,是必须有的。它就是容器对象实现逻辑操作的骨架,在pipeline上配置不同的valve,当需要调用此容器实现逻辑时,就会按照顺序将此pipeline上的所有valve调用一遍,这里可以参考责任链模式;
- Valve:实现具体业务逻辑单元。可以定制化valve(实现特定接口),然后配置在server.xml里。对其包含的所有host里的应用有效。定制化的valve是可选的,但是每个容器有一个缺省的valve,例如engine的StandardEngineValve,是在StandardEngine里自带的,它主要实现了对其子host对象的StandardHostValve的调用,以此类推。
配置的例子有:
<Engine name="Catalina" defaultHost="localhost"> <Valve className="MyValve0"/> <Valve className="MyValve1"/> <Valve className="MyValve2"/> …… <Host name="localhost" appBase="webapps"> </Host> </Engine>
需要注意的是,运行环境中,pipeline上的valve数组按照配置的顺序加载,但是无论有无配置定制化的valve或有多少定制化的valve,每个容器缺省的valve,例如engine的StandardEngineValve,都会在数组中最后一个。
Host
Host是engine的子容器,它是context容器的集合。其标准实现类为:
org.apache.catalina.core.StandardHost
StandardHost的核心模块与StandardEngine差不多。只是作用域不一样,它的模块只对其包含的子context有效。除此,还有一些特殊的逻辑,例如context的部署。Context的部署还是比较多的,主要分为:
- War部署
- 文件夹部署
- 配置部署等
有时间单独再说吧。照例贴个核心模块概念图。
Context
Context是host的子容器,它是wrapper容器的集合。其标准实现类为:
org.apache.catalina.core.StandardContext
应该说StandardContext是tomcat中最大的一个类。它封装的是每个web app。
看一下StandardContext的主要逻辑单元概念图。
Pipeline,valve,realm与上面容器一样,只是作用域不一样,不多说了。
- Manager: 它主要是应用的session管理模块。其主要功能是session的创建,session的维护,session的持久化(persistence),以及跨context的session的管理等。Manager模块可以定制化,tomcat也给出了一个标准实现;
org.apache.catalina.session.StandardManager
manager模块是必须要有的,可以在server.xml中配置,如果没有配置的话,会在程序里生成一个manager对象。
- Resources: 它是每个web app对应的部署结构的封装,比如,有的app是tomcat的webapps目录下的某个子目录或是在context节点配置的其他目录,或者是war文件部署的结构等。它对于每个web app是必须的。
- Loader:它是对每个web app的自有的classloader的封装。具体内容涉及到tomcat的classloader体系,会在一篇文档中单独说明。Tomcat正是有一套完整的classloader体系,才能保证每个web app或是独立运营,或是共享某些对象等等。它对于每个web app是必须的。
- Mapper:它封装了请求资源URI与每个相对应的处理wrapper容器的映射关系。
以某个web app的自有的web.xml配置为例;
<servlet> <servlet-name>httpserver</servlet-name> <servlet-class>com.gearever.servlet.TestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>httpserver</servlet-name> <url-pattern>/*.do</url-pattern> </servlet-mapping>
对于mapper对象,可以抽象的理解成一个map结构,其key是某个访问资源,例如/*.do,那么其value就是封装了处理这个资源TestServlet的某个wrapper对象。当访问/*.do资源时,TestServlet就会在mapper对象中定位到。这里需要特别说明的是,通过这个mapper对象定位特定的wrapper对象的方式,只有一种情况,那就是在servlet或jsp中通过forward方式访问资源时用到。例如,
request.getRequestDispatcher(url).forward(request, response)
关于mapper机制会在一篇文档中专门说明,这里简单介绍一下,方便理解。如图所示。
Mapper对象在tomcat中存在于两个地方(注意,不是说只有两个mapper对象存在),其一,是每个context容器对象中,它只记录了此context内部的访问资源与相对应的wrapper子容器的映射;其二,是connector模块中,这是tomcat全局的变量,它记录了一个完整的映射对应关系,即根据访问的完整URL如何定位到哪个host下的哪个context的哪个wrapper容器。
这样,通过上面说的forward方式访问资源会用到第一种mapper,除此之外,其他的任何方式,都是通过第二种方式的mapper定位到wrapper来处理的。也就是说,forward是服务器内部的重定向,不需要经过网络接口,因此只需要通过内存中的处理就能完成。这也就是常说的forward与sendRedirect方式重定向区别的根本所在。
看一下request.getRequestDispatcher(url) 方法的源码。
public RequestDispatcher getRequestDispatcher(String path) { // Validate the path argument if (path == null) return (null); if (!path.startsWith("/")) throw new IllegalArgumentException (sm.getString ("applicationContext.requestDispatcher.iae", path)); // Get query string String queryString = null; int pos = path.indexOf('?'); if (pos >= 0) { queryString = path.substring(pos + 1); path = path.substring(0, pos); } path = normalize(path); if (path == null) return (null); pos = path.length(); // Use the thread local URI and mapping data DispatchData dd = dispatchData.get(); if (dd == null) { dd = new DispatchData(); dispatchData.set(dd); } MessageBytes uriMB = dd.uriMB; uriMB.recycle(); // Use the thread local mapping data MappingData mappingData = dd.mappingData; // Map the URI CharChunk uriCC = uriMB.getCharChunk(); try { uriCC.append(context.getPath(), 0, context.getPath().length()); /* * Ignore any trailing path params (separated by ';') for mapping * purposes */ int semicolon = path.indexOf(';'); if (pos >= 0 && semicolon > pos) { semicolon = -1; } uriCC.append(path, 0, semicolon > 0 ? semicolon : pos); context.getMapper().map(uriMB, mappingData); if (mappingData.wrapper == null) { return (null); } /* * Append any trailing path params (separated by ';') that were * ignored for mapping purposes, so that they're reflected in the * RequestDispatcher's requestURI */ if (semicolon > 0) { uriCC.append(path, semicolon, pos - semicolon); } } catch (Exception e) { // Should never happen log(sm.getString("applicationContext.mapping.error"), e); return (null); } Wrapper wrapper = (Wrapper) mappingData.wrapper; String wrapperPath = mappingData.wrapperPath.toString(); String pathInfo = mappingData.pathInfo.toString(); mappingData.recycle(); // Construct a RequestDispatcher to process this request return new ApplicationDispatcher (wrapper, uriCC.toString(), wrapperPath, pathInfo, queryString, null); }
红色部分标记了从context的mapper对象中定位wrapper子容器,然后封装在一个dispatcher对象内并返回。通过上面的阐述,也说明了为什么forward方法不能跨context访问资源了。
Wrapper
Wrapper是context的子容器,它封装的处理资源的每个具体的servlet。其标准实现类为:
org.apache.catalina.core.StandardWrapper
应该说StandardWrapper是tomcat中比较重要的一个类。初认识它时,比较容易混淆。
先看一下StandardWrapper的主要逻辑单元概念图。
Pipeline,valve与上面容器一样,只是作用域不一样,不多说了。
主要说说servlet对象与servlet stack对象。这两个对象在wrapper容器中只存在其中之一,也就是说只有其中一个不为空。当以servlet对象存在时,说明此servlet是支持多线程并发访问的,也就是说不存在线程同步的过程,此wrapper容器中只包含一个servlet对象(这是我们常用的模式);当以servlet stack对象存在时,说明servlet是不支持多线程并发访问的,每个servlet对象任一时刻只有一个线程可以调用,这样servlet stack实现的就是个简易的线程池,此wrapper容器中只包含一组servlet对象,它的基本原型是worker thread模式实现的。
那么,怎么来决定是以servlet对象方式存储还是servlet stack方式存储呢?其实,只要在开发servlet类时,实现一个SingleThreadModel接口即可。
如果需要线程同步的servlet类,例如:
public class LoginServlet extends HttpServlet implements javax.servlet.SingleThreadModel{ …… }
但是值得注意的是,这种同步机制只是从servlet规范的角度来说提供的一种功能,在实际应用中并不能完全解决线程安全问题,例如如果servlet中有static数据访问等,因此如果对线程安全又比较严格要求的,最好还是用一些其他的自定义的解决方案。
Wrapper的基本功能已经说了。那么再说一个wrapper比较重要的概念。严格的说,并不是每一个访问资源对应一个wrapper对象。而是每一种访问资源对应一个wrapper对象。其大致可分为三种:
- 处理静态资源的一个wrapper:例如html,jpg等静态资源的wrapper,它包含了一个tomcat的实现处理静态资源的缺省servlet:
org.apache.catalina.servlets.DefaultServlet
- 处理jsp的一个wrapper:例如访问的所有jsp文件,它包含了一个tomcat的实现处理jsp的缺省servlet:
org.apache.jasper.servlet.JspServlet
它主要实现了对jsp的编译等操作
- 处理servlet的若干wrapper:它包含了自定义的servlet对象,就是在web.xml中配置的servlet。
需要注意的是,前两种wrapper分别是一个,主要是其对应的是DefaultServlet及JspServlet。这两个servlet是在tomcat的全局conf目录下的web.xml中配置的,当app启动时,加载到内存中。
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet>
至此,阐述了tomcat的四大容器结构。 有时间接着探讨tomcat如何将这四大容器串起来运作的。
相关推荐
总体架构:1、面向组件架构2、基于JMX3、事件侦听tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成,如Server、Service、Connector等,并基于JMX管理这些组件,另外实现以上接口的组件也...
全套微服务架构,视频学习java微服务架构,包括如下 第1章 微服务简介 001构建单体应用 002微服务解决复杂问题 003微服务的优点 004微服务的缺点 第2章 Linux使用 005Linux 简介 006Linux 与 Windows ...
采用标准的J2EE规范,支持全部流行的商业应用服务器和其它Web容器比如:WebSphere、WebLogic、Tomcat、Jboss、等 注释配置采用JSR-250 规范定义的注释标记 支持流行的关系型数据库:Oracle、Db2、MySQL 等 提供CXF ...
154 Solr 全文搜索引擎-完成测试类 CRUD 功能 155 Solr 全文搜索引擎-实现搜索接口 156 Spring Boot 启用 Profile 157 Docker 私服搭建 158 项目的容器化部署1 159 项目的容器化部署2.1 159 项目的容器化部署2.2 160...
第7章 Tomcat分析44 7.1 Tomcat的顶层结构及启动过程44 7.1.1 Tomcat的顶层结构44 7.1.2 Bootstrap的启动过程45 7.1.3 Catalina的启动过程47 7.1.4 Server的启动过程48 7.1.5 Service的启动过程50 7.2 ...
源码部分包含了项目的核心代码,包括数据库表结构设计、实体类、DAO层接口、Service层接口及实现类、Controller层接口及实现类等。通过阅读源码,开发者可以了解到项目的架构设计、技术选型以及各个模块之间的交互...
- 2、需要把service实现类放到spring容器中管理 ###表现层 - 1、配置注解驱动 - 2、配置视图解析器 - 3、需要扫描controller ###web.xml - 1、spring容器的配置 - 2、spring前端控制器的配置 - 3、post乱码过滤器...
│ 09.FastDFS工具类的使用.avi │ 10.图片上传过程分析.avi │ 11.图片上传Service.avi │ 12.图片上传完成.avi │ 13.解决火狐兼容性问题.avi │ 14.spring的父子容器.avi │ 淘淘商城第三天笔记.docx │ ├─04....
容器类 集合 链表 map 工具类 系统类 日期类 数字类 字符串+正则 流 字符流 字节流 语言特性 继承 封装 多态 JVM 多线程与并发 GC机制 GC收集器类型 串行 CMS 并行 G1 算法 复制 标记...
DataGear是一款数据可视化分析平台,使用Java语言开发,采用浏览器/服务器架构,支持SQL、CSV、Excel、HTTP接口、JSON等多种数据源,主要功能包括数据管理、SQL工作台、数据导入/导出、数据集管理、图表管理、看板...
1.3 J2EE容器 1.3.1 容器服务 1.3.2 容器类型 1.4 J2EE核心技术 1.4.1 Servlet 1.4.2 JSP(Java服务页面) 1.4.3 EJB(企业JavaBean) 1.4.4 JDBC(Java数据库连接) 1.4.5 JTA/JTS(Java事务) 1.4.6 JNDI(Java...
1.3 J2EE容器 1.3.1 容器服务 1.3.2 容器类型 1.4 J2EE核心技术 1.4.1 Servlet 1.4.2 JSP(Java服务页面) 1.4.3 EJB(企业JavaBean) 1.4.4 JDBC(Java数据库连接) 1.4.5 JTA/JTS(Java事务) 1.4.6 JNDI(Java...
1.3 J2EE容器 1.3.1 容器服务 1.3.2 容器类型 1.4 J2EE核心技术 1.4.1 Servlet 1.4.2 JSP(Java服务页面) 1.4.3 EJB(企业JavaBean) 1.4.4 JDBC(Java数据库连接) 1.4.5 JTA/JTS(Java事务) 1.4.6 JNDI(Java...
1.3 J2EE容器 1.3.1 容器服务 1.3.2 容器类型 1.4 J2EE核心技术 1.4.1 Servlet 1.4.2 JSP(Java服务页面) 1.4.3 EJB(企业JavaBean) 1.4.4 JDBC(Java数据库连接) 1.4.5 JTA/JTS(Java事务) 1.4.6 JNDI(Java...
- JAVA容器类 - Java锁汇总 ## 数据库 - MySQL - MySQL数据库开发规范 ## 计算机网络 - 计算机网络 ## 算法 - 数据结构与算法 - LeetCode解题总结 - 海量数据处理总结 ## 操作系统 - 操作系统 - Linux...
数据访问层为了将SQL语句从程序代码中彻底分离,降低耦合度,使用了Mybatis持久层框架,并利用spring的IOC容器管理三层结构的对象及其依赖关系。项目中配置了登录拦截器,需要通过登录验证才能访问系统中的资源。...
采用基于JSP/AJAX+Servlet+Action的MVC架构,采用Struts1.3标准,兼容于Java 2 Standard Edition 1.4和1.5(5.0),兼容Windows/Linux/Unix多种操作系统平台,兼容于Tomcat/Resin/WebLogic/WebSphere等多种JSP服务器...
最新版Java面试宝典,精心提炼核心重点内容简化应用面试实战10秒一道,Java初级,高级,框架,底层原理,数据库,操作系统,微服务,IO,并发,JVM,容器,SpringBoot,SpringCloud,linx,面向对象,常用类,多线程,...