`
yixin416757625
  • 浏览: 20372 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Tomcat 源码学习( 启动框架 )

阅读更多

源文出处:http://webservices.ctocio.com.cn/wsjavtec/72/8113072_2.shtml

 

 

毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的。 所以得实践、实践、再实践。 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动过程。 如果有不明白的地方, 再来查阅本文, 看是否能得到帮助。 我相信这样效果以及学习速度都会好很多!

  1. Tomcat的整体框架结构

  Tomcat的基本框架, 分为4个层次。

  Top Level Elements:

  Server

  Service

  Connector

  HTTP

  AJP

  Container

  Engine

  Host

  Context

  Component

  manager

  logger

  loader

  pipeline

  valve

  ...

  站在框架的顶层的是Server和Service

  Server: 其实就是BackGroud程序, 在Tomcat里面的Server的用处是启动和监听服务端事件(诸如重启、关闭等命令。 在tomcat的标准配置文件:server.xml里面, 我们可以看到“< Server port="8005" shutdown="SHUTDOWN" debug="0">”这里的"SHUTDOWN"就是server在监听服务端事件的时候所使用的命令字)

  Service: 在tomcat里面, service是指一类问题的解决方案。 通常我们会默认使用tomcat提供的:Tomcat-Standalone 模式的service。 在这种方式下的service既给我们提供解析jsp和servlet的服务, 同时也提供给我们解析静态文本的服务。

  Connector: Tomcat都是在容器里面处理问题的, 而容器又到哪里去取得输入信息呢?

  Connector就是专干这个的。 他会把从socket传递过来的数据, 封装成Request, 传递给容器来处理。

 

 

通常我们会用到两种Connector,一种叫http connectoer, 用来传递http需求的。 另一种叫AJP, 在我们整合apache与tomcat工作的时候, apache与tomcat之间就是通过这个协议来互动的。 (说到apache与tomcat的整合工作, 通常我们的目的是为了让apache 获取静态资源, 而让tomcat来解析动态的jsp或者servlet。)

  Container: 当http connector把需求传递给顶级的container: Engin的时候, 我们的视线就应该移动到Container这个层面来了。

  在Container这个层, 我们包含了3种容器: Engin, Host, Context.

  Engin: 收到service传递过来的需求, 处理后, 将结果返回给service( service 是通过 connector 这个媒介来和Engin互动的 ).

  Host: Engin收到service传递过来的需求后,不会自己处理, 而是交给合适的Host来处理。

  Host在这里就是虚拟主机的意思, 通常我们都只会使用一个主机,既“localhost”本地机来处理。

  Context: Host接到了从Host传过来的需求后, 也不会自己处理, 而是交给合适的Context来处理。

  比如: < http://127.0.0.1:8080/foo/index.jsp>;

  < http://127.0.1:8080/bar/index.jsp>;

  前者交给foo这个Context来处理, 后者交给bar这个Context来处理。

  很明显吧! context的意思其实就是一个web app的意思。

  我们通常都会在server.xml里面做这样的配置

  < Context path="/foo" docBase="D:/project/foo/web" />

  这个context容器,就是用来干我们该干的事儿的地方的。

  Compenent: 接下来, 我们继续讲讲component是干什么用的。

  我们得先理解一下容器和组件的关系。

  需求被传递到了容器里面, 在合适的时候, 会传递给下一个容器处理。

  而容器里面又盛装着各种各样的组件, 我们可以理解为提供各种各样的增值服务。

  manager: 当一个容器里面装了manager组件后,这个容器就支持session管理了, 事实上在tomcat里面的session管理, 就是靠的在context里面装的manager component.

  logger: 当一个容器里面装了logger组件后, 这个容器里所发生的事情, 就被该组件记录下来啦! 我们通常会在logs/ 这个目录下看见 catalina_log.time.txt 以及 localhost.time.txt 和localhost_examples_log.time.txt。 这就是因为我们分别为:engin, host以及context(examples)这三个容器安装了logger组件, 这也是默认安装, 又叫做标配。

  loader: loader这个组件通常只会给我们的context容器使用, loader是用来启动context以及管理这个context的classloader用的。

 

 

 

pipline: pipeline是这样一个东西, 当一个容器决定了要把从上级传递过来的需求交给子容器的时候, 他就把这个需求放进容器的管道(pipeline)里面去。 而需求傻呼呼得在管道里面流动的时候, 就会被管道里面的各个阀门拦截下来。 比如管道里面放了两个阀门。 第一个阀门叫做“access_allow_vavle”, 也就是说需求流过来的时候,它会看这个需求是哪个IP过来的, 如果这个IP已经在黑名单里面了, sure, 杀! 第二个阀门叫做“defaul_access_valve”它会做例行的检查, 如果通过的话,OK, 把需求传递给当前容器的子容器。 就是通过这种方式, 需求就在各个容器里面传递,流动, 最后抵达目的地的了。

  valve: 就是上面所说的阀门啦。

  Tomcat里面大概就是这么些东西, 我们可以简单地这么理解tomcat的框架,它是一种自上而下, 容器里又包含子容器的这样一种结构。

  2. Tomcat的启动流程

  这篇文章是讲tomcat怎么启动的,既然我们大体上了解了TOMCAT的框架结构了, 那么我们可以望文生意地就猜到tomcat的启动, 会先启动父容器,然后逐个启动里面的子容器。 启动每一个容器的时候, 都会启动安插在他身上的组件。 当所有的组件启动完毕, 所有的容器启动完毕的时候, tomcat本身也就启动完毕了。

  顺理成章地, 我们同样可以猜到, tomcat的启动会分成两大部分, 第一步是装配工作。 第二步是启动工作。

  装配工作就是为父容器装上子容器, 为各个容器安插进组件的工作。 这个地方我们会用到digester模式, 至于digester模式什么, 有什么用, 怎么工作的. 请参考 < http://software.ccidnet.com/pub/article/c322_a31671_p2.html>;

  启动工作是在装配工作之后, 一旦装配成功了, 我们就只需要点燃最上面的一根导线, 整个tomcat就会被激活起来。 这就好比我们要开一辆已经装配好了的汽车的时候一样,我们只要把钥匙插进钥匙孔,一拧,汽车的引擎就会发动起来,空调就会开起来, 安全装置就会生效, 如此一来,汽车整个就发动起来了。(这个过程确实和TOMCAT的启动过程不谋而和, 让我们不得不怀疑 TOMCAT的设计者是在GE做JAVA开发的)。

  2.1 一些有意思的名称:

  Catalina

  Tomcat

  Bootstrap

  Engin

  Host

  Context

  他们的意思很有意思:

  Catalina: 远程轰炸机

  Tomcat: 熊猫轰炸机 -- 轰炸机的一种(这让我想起了让国人引以为豪的熊猫手机,是不是英文可以叫做tomcat??? , 又让我想起了另一则广告: 波导-手机中的战斗机、波音-客机中的战斗机 )

  Bootstap: 引导

  Engin: 发动机

  Host: 主机,领土

  Context: 内容, 目标, 上下文

  ... 在许多许多年后, 现代人类已经灭绝。 后现代生物发现了这些单词零落零落在一块。 一个自以为聪明的家伙把这些东西翻译出来了:

  在地勤人员的引导(bootstrap)下, 一架轰炸架(catalina)腾空跃起, 远看是熊猫轰炸机(tomcat), 近看还是熊猫轰炸机! 凭借着优秀的发动机技术(engin), 这架熊猫轰炸机飞临了敌国的领土上空(host), 对准目标(context)投下了毁天灭地的核弹头,波~ 现代生物就这么隔屁了~

  综上所述, 这又不得不让人联想到GE是不是也参与了军事设备的生产呢?

 

 

2.2 历史就是那么惊人的相似! tomcat的启动就是从org.apache.catalina.startup.Bootstrap这个类悍然启动的!

  在Bootstrap里做了两件事:

  1. 指定了3种类型classloader:

  commonLoader: common/classes、common/lib、common/endorsed

  catalinaLoader: server/classes、server/lib、commonLoader

  sharedLoader: shared/classes、shared/lib、commonLoader

  2. 引导Catalina的启动。

  用Reflection技术调用org.apache.catalina.startup.Catalina的process方法, 并传递参数过去。

  2.3 Catalina.java

  Catalina完成了几个重要的任务:

  1. 使用Digester技术装配tomcat各个容器与组件。

  1.1 装配工作的主要内容是安装各个大件。 比如server下有什么样的servcie。 Host会容纳多少个context。 Context都会使用到哪些组件等等。

  1.2 同时呢, 在装配工作这一步, 还完成了mbeans的配置工作。 在这里,我简单地但不十分精确地描述一下mbean是什么,干什么用的。

  我们自己生成的对象, 自己管理, 天经地义! 但是如果我们创建了对象了, 想让别人来管, 怎么办呢? 我想至少得告诉别人我们都有什么, 以及通过什么方法可以找到 吧! JMX技术给我们提供了一种手段。 JMX里面主要有3种东西。Mbean, agent, connector.

  Mbean: 用来映射我们的对象。也许mbean就是我们创建的对象, 也许不是, 但有了它, 就可以引用到我们的对象了。

  Agent: 通过它, 就可以找到mbean了。

  Connector: 连接Agent的方式。 可以是http的, 也可以是rmi的,还可以直接通过socket。

  发生在tomcat 装配过程中的事情: GlobalResourcesLifecycleListener 类的初始化会被触发:

  protected static Registry registry = MBeanUtils.createRegistry(); 会运行

  MBeanUtils.createRegistry() 会依据/org/apache/catalina/mbeans/mbeans-descriptors.xml这个配置文件创建 mbeans. Ok, 外界就有了条途径访问tomcat中的各个组件了。(有点像后门儿)

  2. 为top level 的server 做初始化工作。 实际上就是做通常会配置给service的两条connector.(http, ajp)

  3. 从server这个容器开始启动, 点燃整个tomcat.

  4. 为server做一个hook程序, 检测当server shutdown的时候, 关闭tomcat的各个容器用。

  5. 监听8005端口, 如果发送"SHUTDOWN"(默认培植下字符串)过来, 关闭8005serverSocket。

  2.4 启动各个容器

  1. Server

  触发Server容器启动前(before_start), 启动中(start), 启动后(after_start)3个事件, 并运行相应的事件处理器。

  启动Server的子容器:Servcie.

  2. Service

  启动Service的子容器:Engin

  启动Connector

  3. Engin

  到了Engin这个层次,以及以下级别的容器, Tomcat就使用了比较一致的启动方式了。

  首先, 运行各个容器自己特有一些任务

  随后, 触发启动前事件

  立即, 设置标签,就表示该容器已经启动

  接着, 启动容器中的各个组件: loader, logger, manager等等

  再接着,启动mapping组件。(注1)

  紧跟着,启动子容器。

  接下来,启动该容器的管道(pipline)

  然后, 触发启动中事件

  最后, 触发启动后事件。

 

 

 

Engin大致会这么做, Host大致也会这么做, Context大致还是会这么做。 那么很显然地, 我们需要在这里使用到代码复用的技术。 tomcat在处理这个问题的时候, 漂亮地使用了抽象类来处理。 ContainerBase. 最后使得这部分完成复杂功能的代码显得干净利落, 干练爽快, 实在是令人觉得叹为观止, 细细品来, 直觉如享佳珍, 另人齿颊留香, 留恋往返啊!

  Engin的触发启动前事件里, 会激活绑定在Engin上的唯一一个Listener:EnginConfig。

  这个EnginConfig类基本上没有做什么事情, 就是把EnginConfig的调试级别设置为和Engin相当。 另外就是输出几行文本, 表示Engin已经配置完毕, 并没有做什么实质性的工作。

  注1: mapping组件的用处是, 当一个需求将要从父容器传递到子容器的时候, 而父容器又有多个子容器的话, 那么应该选择哪个子容器来处理需求呢? 这个由mapping 组件来定夺。

  4. Host

  同Engin一样, 也是调用ContainerBase里面的start()方法, 不过之前做了些自个儿的任务,就是往Host这个容器的通道(pipline)里面, 安装了一个叫做

  “org.apache.catalina.valves.ErrorReportValve”的阀门。

  这个阀门的用处是这样的: 需求在被Engin传递给Host后, 会继续传递给Context做具体的处理。 这里需求其实就是作为参数传递的Request, Response。 所以在context把需求处理完后, 通常会改动response。 而这个org.apache.catalina.valves.ErrorReportValve的作用就是检察response是否包含错误, 如果有就做相应的处理。

  5. Context

  到了这里, 就终于轮到了tomcat启动中真正的重头戏,启动Context了。

  StandardContext.start() 这个启动Context容器的方法被StandardHost调用.

  5.1 webappResources 该context所指向的具体目录

  5.2 安装defaultContex, DefaultContext 就是默认Context。 如果我们在一个Host下面安装了DefaultContext,而且defaultContext里面又安装了一个数据库连接池资源的话。 那么其他所有的在该Host下的Context, 都可以直接使用这个数据库连接池, 而不用格外做配置了。

  5.3 指定Loader. 通常用默认的org.apache.catalina.loader.WebappLoader这个类。 Loader就是用来指定这个context会用到哪些类啊, 哪些jar包啊这些什么的。

  5.4 指定 Manager. 通常使用默认的org.apache.catalina.session. StandardManager 。 Manager是用来管理session的。

  其实session的管理也很好实现。 以一种简单的session管理为例。 当需求传递过来的时候, 在Request对象里面有一个sessionId 属性。 OK, 得到这个sessionId后, 我们就可以把它作为map的key,而value我们可以放置一个HashMap. HashMap里边儿, 再放我们想放的东西。

  5.5 postWorkDirectory (). Tomcat下面有一个work目录。 我们把临时文件都扔在那儿去。 这个步骤就是在那里创建一个目录。 一般说来会在%CATALINA_HOME%/work/Standalone\localhost\ 这个地方生成一个目录。

  5.6 Binding thread。到了这里, 就应该发生 class Loader 互换了。 之前是看得见tomcat下面所有的class和lib. 接下来需要看得见当前context下的class。 所以要设置contextClassLoader, 同时还要把旧的ClassLoader记录下来,因为以后还要用的。

  5.7 启动 Loader. 指定这个Context具体要使用哪些classes, 用到哪些jar文件。 如果reloadable设置成了true, 就会启动一个线程来监视classes的变化, 如果有变化就重新启动Context。

  5.8 启动logger

  5.9 触发安装在它身上的一个监听器。

  lifecycle.fireLifecycleEvent(START_EVENT, null);

  作为监听器之一,ContextConfig会被启动. ContextConfig就是用来配置web.xml的。 比如这个Context有多少Servlet, 又有多少Filter, 就是在这里给Context装上去的。

  5.9.1 defaultConfig. 每个context都得配置 tomcat/conf/web.xml 这个文件。

  5.9.2 applicationConfig 配置自己的 WEB-INF/web.xml 文件

  5.9.3 validateSecurityRoles 权限验证。 通常我们在访问/admin 或者/manager的时候,需要用户要么是admin的要么是manager的, 才能访问。 而且我们还可以限制那些资源可以访问, 而哪些不能。 都是在这里实现的。

  5.9.4 tldScan: 扫描一下, 需要用到哪些标签(tag lab)

  5.10 启动 manager

  5.11 postWelcomeFiles() 我们通常会用到的3个启动文件的名称:

  index.html、index.htm、index.jsp 就被默认地绑在了这个context上

  5.12 listenerStart 配置listener

  5.13 filterStart 配置 filter

  5.14 启动带有< load-on-startup>1< /load-on-startup>的Servlet.

  顺序是从小到大: 1,2,3… 最后是0

  默认情况下, 至少会启动如下3个的Servlet:

  org.apache.catalina.servlets.DefaultServlet

  处理静态资源的Servlet. 什么图片啊, html啊, css啊, js啊都找他

  org.apache.catalina.servlets.InvokerServlet

  处理没有做Servlet Mapping的那些Servlet.

  org.apache.jasper.servlet.JspServlet

  处理JSP文件的.

  5.15 标识context已经启动完毕。

  走了多少个步骤啊, Context总算是启动完毕喽。

  OK! 走到了这里, 每个容器以及组件都启动完毕。 Tomcat终于不辞辛劳地为人民服务了!

 

 

 

分享到:
评论

相关推荐

    TOMCAT源码分析(启动框架)

    【TOMCAT源码分析(启动框架)】 Tomcat是一款广泛应用的开源Java Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,为Web应用程序提供了运行环境。本篇文章将深入探讨Tomcat的系统框架及其启动流程...

    tomcat源码学习之环境搭建

    在深入探讨Tomcat源码学习之前,我们首先要理解Tomcat是什么。Tomcat是一款开源的、免费的Web服务器和Servlet容器,由Apache软件基金会维护。它实现了Java Servlet和JavaServer Pages(JSP)规范,是Java EE应用...

    TOMCAT源码分析(启动框架).pdf

    ### TOMCAT源码分析——启动框架详解 #### 一、前言 TOMCAT作为一款广泛使用的开源Java Servlet容器,其内部实现复杂且强大。本文旨在深入剖析TOMCAT的启动框架及其整体架构,帮助读者更好地理解其工作原理。...

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

    【标题】:Tomcat8源码学习 在Java Web开发领域,Tomcat是一个非常重要的应用服务器,它作为开源的...对于想要从事中间件开发或者希望提高Java Web性能优化能力的程序员来说,Tomcat源码学习是一条必不可少的道路。

    tomcat9 源码学习

    源码学习对于理解Tomcat的工作原理、优化性能以及自定义功能至关重要。以下是一些在学习Tomcat9源码时会涉及的关键知识点: 1. **架构概述**:Tomcat由多个组件构成,如Catalina(核心Servlet容器)、 Coyote...

    tomcat源码

    【Apache Tomcat源码解析】 Apache Tomcat,作为开源的Java Servlet容器,是实现Java EE Web应用程序规范的主要工具之一。Tomcat 7.0.50版本是它的一个重要里程碑,提供了许多稳定性和性能的改进。这个源码压缩包...

    spring-instrument-tomcat源码

    《深入解析Spring Instrument Tomcat源码》 Spring框架以其强大的功能和灵活性在Java开发领域占据着举足轻重的地位。而Spring Instrument Tomcat模块则是Spring框架中的一个重要组成部分,它为Tomcat服务器提供了类...

    Tomcat源码研究.pdf

    **Tomcat源码研究** Tomcat是一款开源的Java Servlet容器,是Apache软件基金会下的Jakarta项目的一部分。它被广泛用于部署Web应用程序,因为其轻量级、高效且易于理解和定制的特性。以下是对Tomcat源码研究的一些...

    Tomcat源码Tomcat源码

    本文将主要探讨Tomcat的启动框架、核心组件及其相互关系。 首先,Tomcat的整体框架分为四个层次:Top Level Elements、Connector、Container和Component。 1. **Top Level Elements** - **Server**:这是Tomcat的...

    tomcat 7.0源码

    通过深入学习Tomcat 7.0的源码,开发者不仅可以理解Web服务器的工作原理,还能掌握如何优化服务器性能,提升应用的运行效率,同时对Java EE规范有更深入的认识。这将对开发和运维工作带来极大的帮助。

    apache-tomcat-7.0.81-src 源码免费下载

    9. **错误处理与日志系统**:Tomcat使用自定义的日志框架,源码中`logging`目录下的类定义了如何记录和处理错误信息。 10. **网络编程**:Tomcat底层使用NIO(非阻塞I/O)和BIO(阻塞I/O)模型,这在`java/org/...

    tomcat-7.0.90-src-源码

    深入Tomcat源码,我们可以学习到以下关键知识点: 1. **Web应用部署**:Tomcat如何解析`WEB-INF/web.xml`配置文件,加载Servlet和Filter,以及如何根据`META-INF/context.xml`设置上下文参数。 2. **生命周期管理*...

    tomcat源码分析

    总的来说,Tomcat源码分析涉及了从启动流程到核心组件的各个方面,深入学习这些内容能够提升开发者对Web服务器的理解,从而提高开发和维护效率。通过对源码的解读,我们可以更有效地解决性能瓶颈、优化配置,以及...

    Tomcat7.0.68源码

    - **Juli**:Tomcat的自定义日志框架。 - **Shared**:共享的类库,可以在多个组件之间共用。 3. **配置文件解析**: - `server.xml`:Tomcat服务器的主要配置文件,定义了服务器的端口、连接器、引擎、主机等...

    tomcat8.0源码

    《深入剖析Tomcat 8.0源码》 Apache Tomcat 是一款开源的Java Servlet容器,主要用于实现Java Web应用程序的部署与运行。Tomcat 8.0是其一个重要的...总之,Tomcat 8.0源码的探索是一次富有挑战且极具价值的学习旅程。

    spring框架学习源码

    它内置了Tomcat服务器,提供了一种默认的配置,使得开发者可以快速地启动和运行项目。 2. **Eureka**:作为SpringCloud的服务注册与发现组件,Eureka能够帮助服务提供者注册自身,并让服务消费者找到所需的服务。...

    tomcat5.5源代码

    Tomcat使用`java.util.logging`框架记录日志,源码中可以看到`org.apache.juli`包下的自定义日志实现。此外,错误页面的处理也是通过`ErrorReportValve`等组件来实现的。 9. **线程池和并发控制**: Tomcat使用了...

Global site tag (gtag.js) - Google Analytics