1、顶层架构
最顶层的容器是server,代表整个服务器,一个server可以包含至少一个service,用于提供具体服务。
Service主要包含两个部分:Connector和Container。Tomcat的心脏就是这两个组件,作用如下:1、Connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转换;2、Container用于封装和管理Servlet,以及具体处理Request请求。
一个Tomcat只有一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但可以有多个Connector。这是因为一个服务可以有多个连接,如同时提供Http和Https连接。也可以提供相同协议不同端口的连接。
多个 Connector 和一个 Container 就形成了一个 Service,有了 Service 就可以对外提供服务了,但是 Service 还要一个生存的环境,必须要有人能够给她生命、掌握其生死大权,那就非 Server 莫属了!所以整个 Tomcat 的生命周期由 Server 控制。
上述的包含关系,都可以在conf目录下的server.xml配置文件里看出。
Server标签设置的端口号为8005,shutdown=”SHUTDOWN” ,表示在8005端口监听“SHUTDOWN”命令,如果接收到了就会关闭Tomcat。一个Server有一个Service,当然还可以进行配置,一个Service有多个,Service左边的内容都属于Container的,Service下边是Connector。
2、Tomcat顶层架构小结
(1)Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个Connector和一个Container;
(2) Server掌管着整个Tomcat的生死大权;
(4)Service 是对外提供服务的;
(5)Connector用于接受请求并将请求封装成Request和Response来具体处理;
(6)Container用于封装和管理Servlet,以及具体处理request请求;
3、Container架构
Container用于封装和管理Servlet,以及具体处理Request请求,在Connector内部包含了4个子容器
4个子容器的作用分别是:
(1)Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine; (2)Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点; (3)Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件; (4)Wrapper:每一Wrapper封装着一个Servlet;
Context和Host的区别是Context表示一个应用,我们的Tomcat中默认的配置下webapps下的每一个文件夹目录都是一个Context,其中ROOT目录中存放着主应用,其他目录存放着子应用,而整个webapps就是一个Host站点。
我们访问应用Context的时候,如果是ROOT下的则直接使用域名就可以访问,例如:www.ledouit.com,如果是Host(webapps)下的其他应用,则可以使用www.ledouit.com/docs进行访问,当然默认指定的根应用(ROOT)是可以进行设定的,只不过Host站点下默认的主营用是ROOT目录下的。
4、Context
<Context docBase="ROOT11" path="/han" reloadable="true" />在Host标签里。
path:指定访问该web应用的URL入口
docBase:指定访问该WEB应用的文件路径,可以绝对路径,也可以给appBase的相对路径
reloadable:true-如果class文件改动,会自动重新加载web应用
5、webapps
一般将web应用打包成war包格式,然后拷贝到tomcat的webapps目录下进行发布,tomcat、将自动解压war包并生成对应的目录,在内存中动态创建context路径。在正式部署时按照4修改路径!
=====================================================================
Tomcat和Catalina是什么关系?
Tomcat的前身为Catalina,Catalina又是一个轻量级的Servlet容器
Tomcat的前身为Catalina,Catalina又是一个轻量级的Servlet容器。在美国,catalina是一个很美的小岛。所以Tomcat作者的寓意可能是想把Tomcat设计成一个优雅美丽且轻量级的web服务器。Tomcat从4.x版本开始除了作为支持Servlet的容器外,额外加入了很多的功能,比如:jsp、el、naming等等,所以说Tomcat不仅仅是Catalina。
# 什么是Servlet?
所谓Servlet,其实就是Sun为了让Java能实现动态可交互的网页,从而进入Web编程领域而制定的一套标准!
在互联网兴起之初,当时的Sun公司(后面被Oracle收购)已然看到了这次机遇,于是设计出了Applet来对Web应用的支持。不过事实却并不是预期那么得好,Sun悲催地发现Applet并没有给业界带来多大的影响。经过反思,Sun就想既然机遇出现了,市场前景也非常不错,总不能白白放弃了呀,怎么办呢?于是又投入精力去搞一套规范出来,这时Servlet诞生了!
一个Servlet主要做下面三件事情:
- 创建并填充Request对象,包括:URI、参数、method、请求头信息、请求体信息等
- 创建Response对象
- 执行业务逻辑,将结果通过Response的输出流输出到客户端
Servlet没有main方法,所以,如果要执行,则需要在一个容器里面才能执行,这个容器就是为了支持Servlet的功能而存在,Tomcat其实就是一个Servlet容器的实现。
# Tomcat 总结架构
下图应该是网上能找的最好的关于Tomcat的架构图了, 我们来看下它的构成:
从组件的角度看
-
Server: 表示服务器,它提供了一种优雅的方式来启动和停止整个系统,不必单独启停连接器和容器;它是Tomcat构成的顶级构成元素,所有一切均包含在Server中;
-
Service: 表示服务,Server可以运行多个服务。比如一个Tomcat里面可运行订单服务、支付服务、用户服务等等;Server的实现类StandardServer可以包含一个到多个Services, Service的实现类为StandardService调用了容器(Container)接口,其实是调用了Servlet Engine(引擎),而且StandardService类中也指明了该Service归属的Server;
-
Container: 表示容器,可以看做Servlet容器;引擎(Engine)、主机(Host)、上下文(Context)和Wraper均继承自Container接口,所以它们都是容器。
- Engine -- 引擎
- Host -- 主机
- Context -- 上下文
- Wrapper -- 包装器
-
Connector: 表示连接器, 它将Service和Container连接起来,首先它需要注册到一个Service,它的作用就是把来自客户端的请求转发到Container(容器),这就是它为什么称作连接器, 它支持的协议如下:
- 支持AJP协议
- 支持Http协议
- 支持Https协议
-
Service内部还有各种支撑组件,下面简单罗列一下这些组件
- Manager -- 管理器,用于管理会话Session
- Logger -- 日志器,用于管理日志
- Loader -- 加载器,和类加载有关,只会开放给Context所使用
- Pipeline -- 管道组件,配合Valve实现过滤器功能
- Valve -- 阀门组件,配合Pipeline实现过滤器功能
- Realm -- 认证授权组件
# 从web.xml配置和模块对应角度
上述模块的理解不是孤立的,它直接映射为Tomcat的web.xml配置,让我们联系起来看
# 从一个完整请求的角度来看
通过一个完整的HTTP请求,我们还需要把它贯穿起来
假设来自客户的请求为: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源代码分成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编译运行所必需的。
参考资料:Tomcat - 理解Tomcat架构设计 | Java 全栈知识体系 (pdai.tech)
2023-02-23
1、<welcome-file-list>标签
可以设置多个首页<welcome-file>,容器启动后会在根目录下依次查找匹配的物理存在的文件,返回第一个找到的文件,没有找到报404错误。
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index1.jsp</welcome-file>
</welcome-file-list>
默认是用的conf目录下的,但是webapps/ROOT/里的<welcome-file-list>会覆盖conf目录下的。
2、Tomcat部署的三种方式
2.1、在部署目录webapps部署war包
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
...
</Host>
- unpackWARs参数表示,tomcat会对部署在webapps目录中的war文件自动解压,如果为false,则不执行自定解压,但会影响程序的运行效率,
- autoDeploy表示自动部署,即热部署
这种方式也可以直接部署文件夹,但要求部署的文件夹要符合web目录的标准
2.2、在server.xml加入context标签
这种方式需要修改server.xml,不建议使用
2.3、独立的部署文件
首先来到\conf\Catalina目录,
再依据虚拟服务器名称一致的方式,创建一个目录(如:localhost),
建一个xml文件,完成项目部署,文件名与部署项目的上下文名称对应,例如:webdemo.xml
3、Webapps目录下的ROOT目录
tomcat的默认工程目录,用ip:port访问。其他目录访问路径需要加上 /目录名称!
4、conf/context.xml文件
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>
监控资源文件,如果conf/web.xml或者应用下的 WEB-INF/web.xml改变了,会自动加载改变。
5、${catalina.base}
是在catalina.bat启动文件里设置的环境参数值
6、源码走读
BootStrap.load()
Catalina. load()-解析server.xml文件,放入字段对象
StandardServer.initInternal()
service可能有多个,所以循环调用StandardService.initInternal()
StandardEngine.init(),new了一个startStopExecutor,据说是host、context、wrapper的启动线程池,应该是在start里面调线程池启动
如果server.xml有线程池配置,调用StandardThreadExecutor.init()
Connector可能多个,所以循环调用Connector.init()
new一个CoyoteAdapter,
AbstractHttp11Protocol.init()
NioEndPoint.bind()-serverSock.socket().bind(addr,getAcceptCount();
poller线程池大小:pollerThreadCount =Math.min(2,Runtime.getRuntime().availableProcessors())
7、Pipeline管道 List<Valve>阀门
貌似日志就是阀门做的?
StandardWrapperValve里面调servlet
filterChain
Tomcat没有解析请求体,直接用request.getInputstream