TOMCAT的框架结构
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat 部分是Apache 服务器的扩展,但它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
先看两张tomcat的结构图,便于我们理解:
TOMCAT的各层次介绍
Server
其实就是BackGroud程序,在Tomcat里面的Server的用处是启动和监听服务端事件(诸如重启、关闭等命令。在tomcat的标准配置文件:server.xml里面,我们可以看“<Serverport="8005"shutdown="SHUTDOWN"debug="0">;”这里的"SHUTDOWN"就是server在监听服务端事件的时候所使用的命令字)
Service
在tomcat里面,service是指一类问题的解决方案。通常我们会默认使用tomcat提供的:Tomcat-Standalone模式的service。在这种方式下的service既给我们提供解析jsp和servlet的服务,同时也提供给我们解析静态文本的服务。
Connector
Tomcat都是在容器里面处理问题的,而容器又到哪里去取得输入信息呢?
Connector就是专干这个的。他会把从socket传递过来的数据,封装成Request,传递给容器来处理。
通常我们会用到两种Connector,一种叫httpconnectoer,用来传递http需求的。另一种叫AJP,在我们整合apache与tomcat工作的时候,apache与tomcat之间就是通过这个协议来互动的。(说到apache与tomcat的整合工作,通常我们的目的是为了让apache获取静态资源,而让tomcat来解析动态的jsp或者servlet。)
Container
当httpconnector把需求传递给顶级的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>;
前者交给foo这个Context来处理,后者交给bar这个Context来处理。
很明显吧!context的意思其实就是一个webapp的意思。
我们通常都会在server.xml里面做这样的配置
<Contextpath="/foo"docBase="D:/project/foo/web"/>;
这个context容器,就是用来干我们该干的事儿的地方的。
Compenent
接下来,我们继续讲讲component是干什么用的。
我们得先理解一下容器和组件的关系。
需求被传递到了容器里面,在合适的时候,会传递给下一个容器处理。而容器里面又盛装着各种各样的组件,我们可以理解为提供各种各样的增值服务。manager:当一个容器里面装了manager组件后,这个容器就支持session管理了,事实上在tomcat里面的session管理,就是靠的在context里面装的managercomponent.
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的框架,它是一种自上而下,容器里又包含子容器的这样一种结构。
二、Tomcat的启动流程
这篇文章是讲tomcat怎么启动的,既然我们大体上了解了TOMCAT的框架结构了,那么我们可以望文生意地就猜到tomcat的启动,会先启动父容器,然后逐个启动里面的子容器。启动每一个容器的时候,都会启动安插在他身上的组件。当所有的组件启动完毕,所有的容器启动完毕的时候,tomcat本身也就启动完毕了。
顺理成章地,我们同样可以猜到,tomcat的启动会分成两大部分,第一步是装配工作。第二步是启动工作。
装配工作就是为父容器装上子容器,为各个容器安插进组件的工作。启动工作是在装配工作之后,一旦装配成功了,我们就只需要点燃最上面的一根导线,整个tomcat就会被激活起来。这就好比我们要开一辆已经装配好了的汽车的时候一样,我们只要把钥匙插进钥匙孔,一拧,汽车的引擎就会发动起来,空调就会开起来,安全装置就会生效,如此一来,汽车整个就发动起来了。
Tomcat的启动
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方法,并传递参数过去。
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类的初始化会被触发:protectedstaticRegistryregistry=MBeanUtils.createRegistry();会运行
MBeanUtils.createRegistry()会依据/org/apache/catalina/mbeans/mbeans-descriptors.xml这个配置文件创建mbeans.Ok,外界就有了条途径访问tomcat中的各个组件了。(有点像后门儿)
2.为toplevel的server做初始化工作。实际上就是做通常会配置给service的两条connector.(http,ajp)
3.从server这个容器开始启动,点燃整个tomcat.
4.为server做一个hook程序,检测当servershutdown的时候,关闭tomcat的各个容器用。
5.监听8005端口,如果发送"SHUTDOWN"(默认培植下字符串)过来,关闭8005serverSocket。
启动各个容器
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.1webappResources该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.5postWorkDirectory().Tomcat下面有一个work目录。我们把临时文件都扔在那儿去。这个步骤就是在那里创建一个目录。一般说来会在%CATALINA_HOME%/work/Standalone\localhost\这个地方生成一个目录。
5.6Bindingthread。到了这里,就应该发生classLoader互换了。之前是看得见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.1defaultConfig.每个context都得配置tomcat/conf/web.xml这个文件。
5.9.2applicationConfig配置自己的WEB-INF/web.xml文件
5.9.3validateSecurityRoles权限验证。通常我们在访问/admin或者/manager的时候,需要用户要么是admin的要么是manager的,才能访问。而且我们还可以限制那些资源可以访问,而哪些不能。都是在这里实现的。
5.9.4tldScan:扫描一下,需要用到哪些标签(taglab)
5.10启动manager
5.11postWelcomeFiles()我们通常会用到的3个启动文件的名称:
index.html、index.htm、index.jsp就被默认地绑在了这个context上
5.12listenerStart配置listener
5.13filterStart配置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---处理没有做ServletMapping的那些Servlet.
org.apache.jasper.servlet.JspServlet---处理JSP文件的.5.15标识context已经启动完毕。
走了多少个步骤啊,Context总算是启动完毕喽。
OK!走到了这里,每个容器以及组件都启动完毕。Tomcat终于不辞辛劳地为人民服务了!
转载至:http://wangjinlongaisong-126-com.iteye.com/blog/1463635
TOMCAT的框架结构的更多相关文章
- Tomcat源码分析
前言: 本文是我阅读了TOMCAT源码后的一些心得. 主要是讲解TOMCAT的系统框架, 以及启动流程.若有错漏之处,敬请批评指教! 建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, ...
- TOMCAT源码分析(启动框架)
建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的. 所以得实践.实践.再实践. 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动 ...
- tomcat 解析(三)-启动框架
TOMCAT源码分析(启动框架)前言: 本文是我阅读了TOMCAT源码后的一些心得. 主要是讲解TOMCAT的系统框架, 以及启动流程.若有错漏之处,敬请批评指教!建议: 毕竟TOMCAT的框 ...
- TOMCAT源码分析(转)
前言: 本文是我阅读了TOMCAT源码后的一些心得. 主要是讲解TOMCAT的系统框架, 以及启动流程.若有错漏之处,敬请批评指教!建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上 ...
- 贯通tomcat --- 电子书
http://www.educity.cn/jiaocheng/j10865.html 第1章 认识Tomcat [本章导读] Tomcat服务器是一个免费的开放源代码的Web应用服务器.它是Apac ...
- Tomcat一个BUG造成CLOSE_WAIT
之前应该提过,我们线上架构整体重新架设了,应用层面使用的是Spring Boot,前段日子因为一些第三方的原因,略有些匆忙的提前开始线上的内测了.然后运维发现了个问题,服务器的HTTPS端口有大量的C ...
- docker——容器安装tomcat
写在前面: 继续docker的学习,学习了docker的基本常用命令之后,我在docker上安装jdk,tomcat两个基本的java web工具,这里对操作流程记录一下. 软件准备: 1.jdk-7 ...
- Tomcat shutdown执行后无法退出进程问题排查及解决
问题定位及排查 上周无意中调试程序在Linux上ps -ef|grep tomcat发现有许多tomcat的进程,当时因为没有影响系统运行就没当回事.而且我内心总觉得这可能是tomcat像nginx一 ...
- 记一次tomcat线程创建异常调优:unable to create new native thread
测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...
随机推荐
- Spring Data JPA 实例查询
一.相关接口方法 在继承JpaRepository接口后,自动拥有了按"实例"进行查询的诸多方法.这些方法主要在两个接口中定义,一是QueryByExampleExecut ...
- onchange、onclick、onblur等事件区别
onblur:控件在失去焦点的时候触发 OnChange:当控件的内容发生改变时触发该事件 OnClick:点击该控件时触发 OnKeyDown:在控件有焦点的情况下,按下键时发生 OnKeyUp:在 ...
- 【iOS】7.4 定位服务->2.1.3.2 定位 - 官方框架CoreLocation 功能2:地理编码和反地理编码
本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正. 本文相关目录: ================== 所属文集:[iOS]07 设备工具 === ...
- Entity Framework 新手入门友好实例
起因 因为实习的原因,程序之中用到了较多的数据库操作逻辑.如果每一处数据库操作都手写的话,工作量较大且后期不易于维护,所以希望能通过 ORM 框架来解决这两个问题. 在昨天之前,对于 ORM 这个词汇 ...
- iOS开发之数据存储之NSData
1.概述 使用archiveRootObject:toFile:方法可以将一个对象直接写入到一个文件中,但有时候可能想将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象. NSDat ...
- 安装psacct或acct程序包
监视Linux用户活动 我认为,对每个想密切监视其服务器/系统上用户活动的Linux/Unix系统管理员来说,psacct或acct是优秀的.必需的应用程序之一. psacct或acct程序包提供了用 ...
- Flask入门笔记(一)
一.程序的基本结构 1.1 最简单的Flask程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #coding=utf-8 # 初始化 from flask import Fla ...
- js移动端横竖屏检测
方法一:用resize事件来判断,利用屏幕的宽高比,来判断横竖屏 (兼容性较好) (function () { var updateOrientation = function () { var or ...
- 各位Coder看过来
为了丰富博客内容,也为了解决一些实际的问题,现准备出一系列博文,内容为各位回复评论指明需要的知识点,将在近期为你解决并提供还算精要的讲解:评论内容要求 Coder:+需要的技术内容.技术内容不限领域, ...
- jQuery基础学习(二)—jQuery选择器
一.jQuery基本选择器 1.CSS选择器 在学习jQuery选择器之前,先介绍一下之前学过的CSS选择器. 选择器 语法 描述 示例 标签选择器 E { ...