前言:
1.作为Java开发人员,大多都对Tomcat不陌生,由Apache基金会提供技术支持与维护,因为其免费开源且易用,作为Web服务器深受市场欢迎,所以有必要对其进行深入的研究,本系列皆以Tomcat 8.5为研究课题,下载地址:https://tomcat.apache.org/download-80.cgi
如下图,为Apache Tomcat 8.5.24的二进制文件分布情况:
这其中包括的各个系列做下简要说明:
* Core: 核心部分,包括(Linux/Unix,Windows 32/64位的压缩包和安装程序)
* Full documentation: 完整版
* Deployer: 部署依赖
* Extras: 拓展包
* Embedded: 嵌入式的(JMX Remote、Web Service部分)
* Source Code Distributions: 源码资源
2.下图为 apache-tomcat-8.5.23.zip 在windows解压后的目录。
下面是解压后的一些关键目录:
* /bin - 启动和停止服务等批处理文件. ( *.sh) 文件 (为Unix系统)、 (*.bat) 文件 (for Windows系统)是一个功能性的复制文件. 自从Win32 command-line 开始是一些单一的,缺乏功能的组件, 现在有一些拓展性的功能
* /conf - 配置文件和一些相关的DTD文件. 最重要的是 server.xml. 它是这个容器最主要的配置文件.
* /logs - 日志文件会打印到这里
* /webapps - 这里是你的应用程序部署的地方.
3.从最本质上讲,tomcat为一个jsp/servlet容器,首先研究一下Tomcat的架构,如下图:
架构诠释:
1.Server(服务器)是Tomcat构成的顶级构成元素,所有一切均包含在Server中,Server的实现类StandardServer可以包含一个到多个Services,Service的实现类为StandardService调用了容器(Container)接口,其实是调用了Servlet Engine(引擎),而且StandardService类中也指明了该Service归属的Server;
2.Container: 引擎(Engine)、主机(Host)、上下文(Context)和Wraper均继承自Container接口,所以它们都是容器。但是,它们是有父子关系的,在主机(Host)、上下文(Context)和引擎(Engine)这三类容器中,引擎是顶级容器,直接包含是主机容器,而主机容器又包含上下文容器,所以引擎、主机和上下文从大小上来说又构成父子关系,虽然它们都继承自Container接口。
3.连接器(Connector)将Service和Container连接起来,首先它需要注册到一个Service,它的作用就是把来自客户端的请求转发到Container(容器),这就是它为什么称作连接器的原因。
从功能的角度将Tomcat源代码分成5个子模块,分别是:
Jsper模: 这个子模块负责jsp页面的解析、jsp属性的验证,同时也负责将jsp页面动态转换为java代码并编译成class文件。在Tomcat源代码中,凡是属于org.apache.jasper包及其子包中的源代码都属于这个子模块;
Servlet和Jsp模块: 这个子模块的源代码属于javax.servlet包及其子包,如我们非常熟悉的javax.servlet.Servlet接口、javax.servet.http.HttpServlet类及javax.servlet.jsp.HttpJspPage就位于这个子模块中;
Catalina模块: 这个子模块包含了所有以org.apache.catalina开头的java源代码。该子模块的任务是规范了Tomcat的总体架构,定义了Server、Service、Host、Connector、Context、Session及Cluster等关键组件及这些组件的实现,这个子模块大量运用了Composite设计模式。同时也规范了Catalina的启动及停止等事件的执行流程。从代码阅读的角度看,这个子模块应该是我们阅读和学习的重点。
Connector模块: 如果说上面三个子模块实现了Tomcat应用服务器的话,那么这个子模块就是Web服务器的实现。所谓连接器(Connector)就是一个连接客户和应用服务器的桥梁,它接收用户的请求,并把用户请求包装成标准的Http请求(包含协议名称,请求头Head,请求方法是Get还是Post等等)。同时,这个子模块还按照标准的Http协议,负责给客户端发送响应页面,比如在请求页面未发现时,connector就会给客户端浏览器发送标准的Http 404错误响应页面。
Resource模块: 这个子模块包含一些资源文件,如Server.xml及Web.xml配置文件。严格说来,这个子模块不包含java源代码,但是它还是Tomcat编译运行所必需的。
JNDI诠释:
1.Java命名和目录接口(JNDI)是一个应用程序编程接口(API),它为使用Java编程语言编写的应用程序提供命名和目录功能。它被定义为独立于任何特定的目录服务实现。因此,各种目录——新的、新兴的、已经部署的目录可以以一种通用的方式访问。
2.JNDI体系结构由一个API和一个服务提供者接口(SPI)组成。Java应用程序使用JNDI API来访问各种命名和目录服务。SPI允许以透明的方式插入各种命名和目录服务,从而允许Java应用程序使用JNDI API访问它们的服务。
见下图:
3.JNDI包含在Java SE平台中。要使用JNDI,您必须拥有JNDI类和一个或多个服务提供者。
JDK包括了以下名称/目录服务的服务提供者:
* 轻量级目录访问协议(LDAP)
* 公共对象请求代理体系结构(CORBA)公共对象服务(COS)名称服务
* Java远程方法调用(RMI)注册表
* 域名服务(DNS)
其他服务提供者可以从JNDI页面下载,也可以从其他供应商那里获得。
JNDI被分为5个包:
* javax.naming
* javax.naming.directory
* javax.naming.ldap
* javax.naming.event
* javax.naming.spi
4.Tomcat运行流程
假设来自客户的请求为:http://localhost:8080/test/index.jsp 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector,然后
* Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应
* Engine获得请求localhost:8080/test/index.jsp,匹配它所有虚拟主机Host
* Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
* localhost Host获得请求/test/index.jsp,匹配它所拥有的所有Context
* Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为""的Context去处理)
* path="/test"的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet
* Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类,构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
* Context把执行完了之后的HttpServletResponse对象返回给Host
* Host把HttpServletResponse对象返回给Engine
* Engine把HttpServletResponse对象返回给Connector
* Connector把HttpServletResponse对象返回给客户browser
后续将讲述Tomcat详细的源码分析,敬请期待,谢谢支持。