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

Tomat6源代码学习(整体架构)[转]

阅读更多

最近学习Tomcat源代码,下面是认为比较好的一篇文章。

原文地址:http://carllgc.blog.ccidnet.com/blog-htm-do-showone-uid-4092-type-blog-itemid-272088.html



我们已经成功将 Tomcat6.0 的源代码导入到 IDE 中。现在我们就开始学习 Tomcat 源码。 Tomcat 源代码共有 1000 多个 java 类,代码行数大约 28 万到 30 万行左右。从项目规模上说,可算得上是一个中型项目。

要学习理解 Tomcat 源代码,有多种办法可行。最原始的一种办法就是,打开 Debugger ,逐行跟踪,看看 Tomcat 如何启动,如何处理客户端请求,如何编译动态 jsp 页面。第二种办法是利用逆向工程,把 Tomcat 的总体类图先描绘出来,然后再结合 sequence diagram ,来学习理解它。我们在这里采取从顶到底的阅读方法,先了解整体架构,然后逐步细化。所谓“纲举目张”,说的就是这个道理。

首先,我们可以从功能的角度将 Tomcat 源代码分成 5 个子模块,它们分别是:

1)   Jsper 子模块

这个子模块负责 jsp 页面的解析, jsp 属性的验证,同时也负责将 jsp 页面动态转换为 java 代码并编译成 class 文件。在 Tomcat 源代码中,凡是属于 org.apache.jasper 包及其子包中的源代码都属于这个子模块;


2)   Servlet Jsp 规范的实现模块

这个子模块的源代码属于 javax.servlet 包及其子包,如我们非常熟悉的 javax.servlet.Servlet 接口、 javax.servet.http.HttpServlet 类及 javax.servlet.jsp.HttpJspPage 就位于这个子模块中;


3)   Catalina 子模块

这个子模块包含了所有以 org.apache.catalina 开头的 java 源代码。该子模块的任务是规范了 Tomcat 的总体架构,定义了 Server Service Host Connector Context Session Cluster 等关键组件及这些组件的实现,这个子模块大量运用了 Composite 设计模式。同时也规范了 Catalina 的启动及停止等事件的执行流程。从代码阅读的角度看,这个子模块是我们阅读和学习的重点。


4)   Connectors 子模块

如果说上面三个子模块实现了 Tomcat 应用服务器的话,那么这个子模块就是 Web 服务器的实现。所谓连接器 (Connector) 就是一个连接客户和应用服务器的桥梁,它接收用户的请求,并把用户请求包装成标准的 Http 请求 ( 包含协议名称,请求头 Head ,请求方法是 Get 还是 Post 等等 ) 。同时,这个子模块还按照标准的 Http 协议,负责给客户端发送响应页面,比如在请求页面未发现时,connector就会给客户端浏览器发送标准的 Http 404 错误响应页面。

Tomcat 实现了两类连接器,除了上述实现了 Http1.1 协议的 Coyote 连接器外,还有一种 JK 连接器,JK 连接器是将Tomcat 和第三方 Web 服务器 ( Apache IIS Web 服务器 ) 连接起来, Tomcat 此时充当应用服务器的角色,负责处理和解释 Jsp Servlet 请求。

Coyote 连接器的源代码位于以 org.apache.coyote 开头的包中, JK 连接器的代码位于以 org.apache.jk 开头的包中。

另外, Tomcat 虽然实现了 Web 服务器的功能,但是其实现不是非常完美,效率不高,所以在生产环境中,我们通常要将 Tomcat Apache Web Server 配合使用,尽量利用它们各自的优势。


5)   Resource 子模块

这个子模块包含一些资源文件,如 Server.xml Web.xml 配置文件。严格说来,这个子模块不包含 java 源代码,但是它还是 Tomcat 编译运行所必需的。


上面我们从模块组件的角度,简单介绍了 Tomcat 的子模块划分及其相应的功能。下面我们简单以图示意之。




从上面的 Tomcat 子模块示意图中,我们可以看到,来自客户端的请求首先由 Connector 子模块进行处理,然后根据情况或者发送到第三方的 Web 服务器,或者转发到 Jsper 模块进行处理,或者转发到 Jsp/Servlet 子模块处理。总体说来, Tomcat 通过下面三种方式处理来自客户端的请求:

(1)   如果客户端发出静态页面请求,如果没有配置第三方 Web 服务器,此时客户端的请求直接交由 Coyote Connector 子模块处理,然后返回结果;如果配有第三方应用服务器,那么客户的请求直接由第三方应用服务器响应,然后返回静态记过页面。客户端请求的执行过程如图中绿线所示。


(2)   如果客户端请求 Jsp 页面,该请求首先转发到发送 Coyote 连接器 ( 在没有配置第三方 Web 服务器的情况下 ) ,或者经过第三方 Web 服务器将客户请求转发到 JK 连接器;然后该 Jsp 请求将交给 Jsper 子模块处理, Jsper 将根据情况验证编译该 Jsp 页面,最后由 Jsp/Servlet 模块对客户请求进行处理。 Jsp 请求处理完毕,服务器首先把响应结果发送给连接器子模块,连接器子模块根据情况或将响应结果页面发送到第三方 Web 服务器,或者直接发送响应结果页面到客户端。


(3)   如果客户请求 Servlet Tomcat 的处理流程和 Jsp 页面的请求执行流程基本类似,只不过少了一个 Jsper 子模块处理罢了。



下面,我们重点针对 Catalina 子模块,熟悉Tomcat的几个关键组件。

(1)   服务器
(Server)  
Tomcat 中,服务器代表整个 J2EE 容器,所有的服务及服务上下文均包含在服务器内。我们打开 Tomcat 源代码,可以看到 org.apache.catalina.Server 这个接口,其中比较重要的方法有 initialize( 负责 Tomcat 启动前的初始化工作 ) ,还有一些服务 (Services) 管理方法,比如 removeService() addService() findService() 之类的方法。


Tomcat 运行时,我们永远只有一个 Server 实例,这不由让我们联想到单例模式 (Singleton Pattern) 。不错,在 Tomcat 中, Server 的实例化工作正是由一个叫 ServerFactory 工厂类完成的,这个工厂类实现了单例设计模式。


比较有意思的是,这个工厂类的产品创建方法名为 getServer() 而不是标准的 createServer() 方法,并且没有加 synchronized synchronized(this) 保护,这是为什么呢?我们知道,在应用单例模式时,需要注意的一个关键点就是多线程的调用问题,如果我们的工厂类在创建单例对象时,这个工厂类有可能被多个线程并发调用的话,那么最好给这个工厂方法加上 synchronized 以避免产生两个不同的产品类实例。如果您想避免 synchronized 的锁机制造成的性能损失,请使用双重检查机制 (double-checked locking) 。所以,如果考虑多线程,这个工厂类的 getServer() 方法应该写成:(红色代码是作者另加上的,源代码中没有)。


/**

* Return the singleton <code>Server</code> instance for this JVM.

*/

public static Server getServer() {

if( server==null ){
synchronized (ServerFactory.class) {
if(server==null){
  server=new StandardServer();
}
}

}
return (server);
}

为什么 Tomcat 在实现时没有加上面的红色代码呢?这是因为, Tomcat 启动时创建 Server 对象,不可能出现多线程情况,所以就免掉了双重检查。如果我们确信没有多线程调用我们的单例工厂类,我们也可以这样做。

另外,如果您对 ServerFactory 进行调试,您会发现一个非常有趣的现象,这个工厂先执行的不是 create 方法 ( 此处为 getServer 方法 ) ,而是 setServer 方法。这意味着这个工厂方法其实并不生产实际产品,实际产品是从别处产生,然后通过 setServer 方法注册到这个 Factory 。当下次有客户请求产品时,这个工厂方法只是简单的把现成的单例产品传给客户。所以这个类其实只需一个单例类足矣,根本没有必要使用工厂模式,所以 Tomcat 的开发者也觉得不好意思使用标准的工厂方法 createProduct ,杀鸡焉用宰牛刀,对吗?


Tomcat6.0 中,服务器 (Server) 接口的实现类只有一个,那就是 org.apache.catalina.core. StandardServer 类。这是一个标准的服务器实现类,这个类不但实现了 Server 接口,而且还实现了 Lifecycle MBeanRegistration 接口, Lifecycle 主要提供了服务器的生命周期管理功能,比如说启动、停止等方法,而 MBeanRegistration 接口是为了将 server 注册到 MBean 服务器,以便在 Tomat 运行时,我们能通过 JMX 来管理服务器。


Tomcat5.0 开始, Tomcat 的开发人员在 JMX 管理上着实下了一番功夫,争取做到让 Tomcat 具有 JBoss 那样非常强大的管理功能。


(2)   服务
(Service)
在上述的标准服务器 (StanderServer.java) 实现代码中,我们可以看到其中有一个 services 的数组,这个数组就是用来存储服务 (Service) 的。所以,我们可以这样理解,一个服务器可能有一至多个服务组成。所谓服务,就是包含一至多个连接器的组件,能够对用户请求作出响应的组件。打开 org.apache.catalina.Service.java 的源代码,我们可以看到其中含有一个连接器数组 (Connector[]) ,这表明一个 Service 有可能包含一个到多个连接器。但所有这些连接器都属于一个引擎 (Engine Container) 。在 Tomcat6 中, org.apache.catalina.Service 接口由 org.apache.catalina.core. StandardService 类来实现的。


(3)   引擎
(Engine)
对一个具体的服务 (service) 来说,引擎是一个用户请求的处理管道,这个管道很特别,因为它只处理 Servlet 请求,在 Tomcat 中,引擎其实就是指 Servlet 引擎。引擎从这些连接器那里接收到 Servlet 请求,然后处理它们,并将响应的结果传回到适当的连接器,从而将响应发送到客户端。简单地说,引擎的功能就是如何处理用户的 Servlet 请求。


org.apache.catalina.Engine 这个接口继承自 org.apache.catalina.Container ,说明引擎是一种特殊的 Container ,是一种专门用来处理 servlet 请求的容器。


(4)   主机
(Host)
Tomcat 服务器来说,主机是 Tomcats 所在机器的网络名 ( 域名 ) 。一个引擎可能包含多个主机,主机支持网络别名。例如,用户通过配置 config.xml 里面的主机 (Host) 元素,让 www.abc.com
abc.com 指向同一台 Tomcat 应用服务器。

(5)   连接器
(Connector)
Tomcat 中,连接器负责和客户端进行请求响应的交流。 Tomcat 中有两种连接器 (Coyote JK 连接器 ) Coyote 连接器实现了 Http1.1 协议,我们可以将它理解为 Tomcat Web 服务器部分。 JK 连接器负责处理来自第三方 Web 服务器的请求,并将请求结果发送给第三方 Web 服务器。针对 Apache Httpd Web 服务器, JK 连接器实现了 AJP 协议。


Tomcat6.0 中,实现 Coyote 连接器的类是 org.apache.catalina.connector.Connector

(6)   上下文
(Context)
上下文代表某一具体的 Web 应用,一个主机可包含多个 Web 应用,所以可有多个 Web 应用上下文,不同的上下文可用不同路径来表示。上下文里含有一些关于该 Web 应用的一些具体信息,比如欢迎页面的文件名, web.xml 文件的位置等等信息。


上下文在 Tomcat 的源码中对应 org.apache.catalina.Context 接口,其具体实现为 org.apache.catalina.core.StandardContext


至此为止,我们熟悉了 Tomcat 架构中一些重要组件。下面我们用 UML 类图 (Class Diagram) 来总结一下。



在上面的类图中,我们先撇开Tomcat 组件不谈,首先给我们印象最深刻的一点是:针对接口编程,而非针对具体实现编程 (Program to interface, not implementation) 。人家老外这点确实值得我们学习。上面的类图中,共有 7 个类,其余均为接口,这些类无一例外地调用了接口,而非具体的实现类。 ServerFactory 调用了 Server 接口,而非 StandServer 的实现类; Connector 类调用了 Service 接口和 Container 接口,而没有调用它们的实现类; StandardService 类调用了 Container 接口和 Server 接口,也同样没有调用它们的实现类。所以我们在编程时,也要贯彻这条原则。


<<Head First Design Patterns>> 一书里,作者举了个非常生动的例子,请看下面三段代码:


a)   代码片段一

Dog d=new Dog();
d.bark();

b)   代码片段二

Animal animal=new Dog();
animal.makeSound();

c)   代码片段三

Animal animal = getAnimal();
animal.makeSound();

作者详细解释了上面第三段代码为什么是最好的,而第二段又为什么比第一段好的道理。东扯西拉这么多,现在我们切入正题。


从上面的类图中,我们可以非常清晰地理解 Tomcat 的总体架构:


a)   Server( 服务器 ) Tomcat 构成的顶级构成元素,所有一切均包含在 Server 中, Server 的实现类 StandardServer 可以包含一个到多个 Services


b)   次顶级元素 Service 的实现类为 StandardService 调用了容器 (Container) 接口,其实是调用了 Servlet Engine( 引擎 ) ,而且 StandardService 类中也指明了该 Service 归属的 Server


c)   接下来次级的构成元素就是容器 (Container) ,主机 (Host) 、上下文 (Context) 和引擎 (Engine) 均继承自 Container 接口,所以它们都是容器。但是,它们是有父子关系的,在主机 (Host) 、上下文 (Context) 和引擎 (Engine) 这三类容器中,引擎是顶级容器,直接包含是主机容器,而主机容器又包含上下文容器,所以引擎、主机和上下文从大小上来说又构成父子关系,虽然它们都继承自 Container 接口。


d)   连接器 (Connector) 没有接口 ( 这可是违反了面向接口编程的原则哟! ) ,它直接实现了 Http1.1 协议。连接器将 Service Container 连接起来,首先它需要注册到一个 Service ,它的作用就是把来自客户端的请求转发到 Container( 容器 ) ,这就是它为什么称作连接器的原因。


下面我们来小结一下, Tomcat 的架构从功能的角度,可以分成 5 个子模块,它们分别是 Connector 子模块, Jsper 子模块, Servlet 子模块, Catalina 子模块和 Resource 子模块,每个子模块负责一定的功能;从组件的角度,我们可以看到 Tomcat 中至少有 7 个关键组件,它们 Server 组件、 Service 组件、 Container 组件、 Connector 组件及继承自 Container 组件的 Host 组件、 Engine 组件和 Container 组件,从 UML Class Diagram 中,我们可以非常明确地理解它们的包容关系。到此为止,希望我们能对 Tomcat 的架构有一个比较清晰的认识。


分享到:
评论

相关推荐

    深入剖析Tomcat源码

    总的来说,《深入剖析Tomcat源码》的源代码不仅提供了一个学习服务器工作原理的实例,也是提升Java EE开发者技能的重要资源。通过深入学习和实践,我们可以更好地理解和定制Tomcat,从而提升我们的Web应用开发和运维...

    看透springMvc源代码分析与实践.pdf

    解压后大小(57.7M) 国内资深Web开发专家根据Spring MVC全新技术撰写,基于实际生产环境,从基础知识、源代码和实战3个维度对Spring MVC的结构和...学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。

    看透springMvc源代码分析与实践-扫描版本

    看透springMvc源代码分析与实践-扫描版本 解压后大小(57.7M) 国内资深Web开发专家根据Spring MVC全新技术撰写,基于实际生产环境,从基础知识... 学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。

    博客系统项目_源代码

    以上就是关于"博客系统项目_源代码"所涉及的主要技术点和开发流程,对于学习和理解Web应用开发,特别是基于Java的B/S架构系统,有着重要的参考价值。通过深入研究这个项目,开发者能够提升自己的技术水平,理解Web...

    tomcat 源码分析系列文档

    7. "tomcat源码分析之一架构.pdf":可能涵盖了Tomcat的整体架构,包括Catalina、 Coyote、Jasper等主要模块的功能和相互关系。 8. "HTTP协议详解.pdf":作为基础,此文档提供了HTTP协议的详细讲解,帮助读者理解...

    Android 社交App+java web后台整套源代码

    在本资源中,我们拥有一套完整的Android社交应用与Java Web后台系统的源代码,这为开发者提供了一个绝佳的学习和实践平台。这套源代码是基于Android Studio和MyEclipse开发的,涵盖了客户端应用和服务器端服务的全部...

    tomcat底层原理深入学习

    当JSP文件被请求时,Jasper将其转换为Java源代码,再编译成Servlet,最后由Catalina调用执行。Jasper还支持JSP的预编译,提高应用启动速度。 5. **线程模型与并发** Tomcat采用两种线程模型:基于线程池的BIO...

    汽车租赁系统 源代码

    汽车租赁系统源代码的分析和学习可以涵盖从基础的编程概念到复杂的系统设计原则,对于理解Java Web应用的开发流程和实践有着重要的价值。通过深入研究源代码,开发者不仅可以学习到具体的技术实现,还能领悟到如何...

    tomcat8 源码学习,欢迎大家下载,官网下载会出现下载不了的情况

    这个压缩包包含了Tomcat8.5.9的完整源代码,它是基于Java语言实现的,包含了服务器的启动、管理、请求处理等核心模块。 源码学习的主要知识点包括: 1. **架构设计**:了解Tomcat的整体架构,如Catalina(核心处理...

    Tomcat源码apache-tomcat-8.5.47-src.zip

    学习Tomcat源码时,可以先从整体架构出发,了解各个组件的作用和交互方式,然后再深入到具体类的实现。通过阅读源码,我们可以理解Tomcat如何处理请求,如何管理Web应用,以及如何实现JSP的生命周期。此外,还可以...

    apache-tomcat-7.0.52 解压免安装版tomcat7

    Jasper将JSP转换为Java源代码,然后编译成Servlet。 4. **Juli**:这是Tomcat的内置日志系统,可以提供详细的错误和诊断信息。 5. **Cluster**:在需要高可用性和负载均衡的环境中,Tomcat的集群功能可以将Web应用...

    JavaWeb源代码方便结合文档学习

    JavaWeb是一种基于Java技术的Web应用开发框架,它包含了Servlet、JSP(JavaServer Pages)、JSTL(JavaServer ...在学习过程中,建议先理解整体架构,然后逐个剖析各个组件,最后动手实践,调试代码,以巩固理论知识。

    Tomcat9 64位

    Apache Tomcat是一个开放源代码的Java Servlet容器,主要用于实现Java Servlet和JavaServer Pages(JSP)技术。作为Java EE Web应用服务器的一部分,Tomcat是轻量级的,相比其他全面的Java应用服务器如JBoss、...

    电商网站源代码(servlet)

    【电商网站源代码(servlet)】是一个基于Java Servlet技术构建的限时抢购平台项目,主要针对初学者设计,...通过深入研究和改进这个项目,学习者可以提升对Servlet、数据库操作、前端技术以及Web应用整体架构的理解。

    看透springMvc源代码分析与实践

     学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。 【电子版来自互联网,仅供预览及学习交流使用,不可用于商业用途,如有版权问题,请联系删除,支持正版,喜欢的 请购买正版书籍: ...

    apache2.2和tomcat6整合

    - **Apache 2.2**: Apache 是一款广泛使用的开放源代码 Web 服务器软件,其稳定性和安全性得到了业界的普遍认可。 ##### 2.2 配置 Apache 代理模块 为了实现 Apache 和 Tomcat 的整合,需要在 Apache 中配置代理...

    30套JSP网站源代码合集.pdf

    这些代码集合可以作为学习资料,帮助开发者快速掌握JSP开发技术,理解JSP与数据库的交互过程,以及Web应用的整体架构设计。 例如,网上购物系统项目源代码包含了用户浏览商品、加入购物车、在线结算等功能;而JSP...

    apache-tomcat-7.0.14-src.zip

    在"apache-tomcat-7.0.14-src.zip"压缩包中,包含了Tomcat7的完整源代码,对于学习和研究Tomcat的架构、性能优化或扩展功能非常有价值。 首先,"pom.xml"文件的添加表明此源码已经被转换为一个Maven项目,Maven是...

    tomcat-connectors-1.2.48-src

    `tomcat-connectors-1.2.48-src`是这个连接器的源代码包,它包含构建和理解Tomcat连接器工作方式所需的所有文件。 1. **连接器的基本结构** Tomcat的连接器由两个主要部分组成:`mod_jk`(Apache HTTPD的模块)和`...

    在线教学系统网站开发源代码+视屏讲解

    本资源包含在线教学系统网站的开发源代码以及配套的视频讲解,为开发者提供了一个全面了解此类系统构建过程的机会。 首先,我们要关注的是标签中的"JSP源码"。JSP(JavaServer Pages)是Java技术的一种,用于创建...

Global site tag (gtag.js) - Google Analytics