背景

Tomcat是一个非常重要的Web Server,已经存在多年。尤其是最近几年,因为Spring MVC或是Spring Boot的盛行,Tomcat的地位越发重要,地位明显升级。
 
我相信很多人一般只是停留在使用的基础上,但是想利用Tomcat实现一些复杂的场景或者高级同功能,我们就需要进一步学习,也需要我们把Tomcat的基础弄清楚。
 
本文将通过大量代码和实例详细讲解Tomcat的基础知识,以便我们对Tomcat有个一个整体深入的认识。
 
本文的代码基于Tomcat 9. 代码地址在https://github.com/apache/tomcat

Tomcat和Catalina的来历

大家都在使用Tomcat,但是我问Tomcat的来历是什么,为什么要会用Catalina,我认为不是每个人都知道。是的,Tomcat和Catalina是2个非常重要的名词,在Tomcat软件和配置里随处可见,但是为什么作者取这样的名字呢?据说,当时作者Craig写代码时,家里的猫有时候不停的跳来跳去,所以最后有Tomcat的取名,那Catalina呢?作者有一个非常喜欢的岛,叫Catalina Island,据说这个岛尽管作者知道,但是还没去过,不知道现在去过没有。所以就用Catalina取名了。
在这个岛上有个镇,叫Avalon,Tomcat曾经取过Avalon的名字,只不过后来放弃了。

Tomcat配置文件

了解Tomcat的结构,最直接的办法是从Tomcat的配置文件看起。下面是Tomcat的配置文件(conf/server.xml),这个是Tomcat源码里的默认配置文件。
为了简单,我删除了一些注释等。

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources> <!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note: A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html --> <!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine name="Catalina" defaultHost="localhost"> <!-- Use the LockOutRealm to prevent attempts to guess user passwords
via a brute-force attack -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm> <Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"> <!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" /> </Host>
</Engine>
</Service>
</Server>
我们可以看到Server、Service、Connector、Engine、Host等。那么它们之间有什么关系呢?

从以上可以看出,Tomcat最顶层的容器叫Server,代表整个服务器,Server中包一个或多个Service,该Service用来代表一个服务。同时,一个Service也包含多个Connector,Connector用来网络连接,例如HTTP,HTTPS或AJP。Service也包含一个或多个Engine等,用来管理和封装Servlet,以及处理具体的请求等。

我们先简要解释一下Tomcat的这个配置文件。

Server
Server的配置文件如下:
<Server port="8005" shutdown="SHUTDOWN"> 
port是8005,也就是说端口8005会监听SHUTDOWN的命令,当我们使用tomcat目录下的bin/shutdown.sh去停止Tomcat时,就会往8005端口发送一个SHUTDOWN的命令。当然,如果端口8005关闭了,执行shutdown.sh脚本就会报错,只能kill Tomcat的进程了。
 
Listener
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> 
先看第一个VersionLoggerListener,其实就是打印Tomcat的一些相关信息,例如版本号,OS信息,Java版本信息等。
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
log();
}
} private void log() {
log.info(sm.getString("versionLoggerListener.serverInfo.server.version",
ServerInfo.getServerInfo()));
log.info(sm.getString("versionLoggerListener.serverInfo.server.built",
ServerInfo.getServerBuilt()));
log.info(sm.getString("versionLoggerListener.serverInfo.server.number",
ServerInfo.getServerNumber()));
log.info(sm.getString("versionLoggerListener.os.name",
System.getProperty("os.name")));
log.info(sm.getString("versionLoggerListener.os.version",
System.getProperty("os.version")));
log.info(sm.getString("versionLoggerListener.os.arch",
System.getProperty("os.arch")));
log.info(sm.getString("versionLoggerListener.java.home",
System.getProperty("java.home")));
log.info(sm.getString("versionLoggerListener.vm.version",
System.getProperty("java.runtime.version")));
log.info(sm.getString("versionLoggerListener.vm.vendor",
System.getProperty("java.vm.vendor")));
log.info(sm.getString("versionLoggerListener.catalina.base",
System.getProperty("catalina.base")));
log.info(sm.getString("versionLoggerListener.catalina.home",
System.getProperty("catalina.home"))); if (logArgs) {
List<String> args = ManagementFactory.getRuntimeMXBean().getInputArguments();
for (String arg : args) {
log.info(sm.getString("versionLoggerListener.arg", arg));
}
} if (logEnv) {
SortedMap<String, String> sortedMap = new TreeMap<>(System.getenv());
for (Map.Entry<String, String> e : sortedMap.entrySet()) {
log.info(sm.getString("versionLoggerListener.env", e.getKey(), e.getValue()));
}
} if (logProps) {
SortedMap<String, String> sortedMap = new TreeMap<>();
for (Map.Entry<Object, Object> e : System.getProperties().entrySet()) {
sortedMap.put(String.valueOf(e.getKey()), String.valueOf(e.getValue()));
}
for (Map.Entry<String, String> e : sortedMap.entrySet()) {
log.info(sm.getString("versionLoggerListener.prop", e.getKey(), e.getValue()));
}
}
 
再看看AprLifecycleListener。其实主要是实现在Tomcat的生命周期里,APR的初始化,创建和销毁等。
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
它们都会实现接口LifecycleListener。该接口为某些事件定义一个listener,这里的事件,其实就是组件的启动和停止事件。但是组件需要实现Tomcat生命周期的接口。这个在后面讲。
 
接下来就是GlobalNamingResources,它定义一些全局的JNDI资源,例如数据库连接等,JNDI意思是Java Naming and Directory interface。
 
然后就是Service,name为Catalina.继续往下看,接下来就是Connector,它主要用来处理网络连接,封装消息包,不同的协议会有不同的处理方式,例如port为8080,协议为HTTP/1.1,会有对应的ProtocolHander来处理,这会在后面解释。可以拥有多个Connector。
下面就是Engine,有点类似虚拟主机的意思,有个defaultHost属性,是指在找不到虚拟主机时用的。Realm主要用来做安全域,后面也会降到。
 
Valve是Tomcat一个非常重要的概念,和Pipeline配合使用,在这里设置的是一个关于Tomcat log的Valve,主要用于将Tomcat的日志以某种格式打印到往到文件,className是其实现类,prefix是日志文件的前缀,suffix是后缀,2者组合起来就是文件名了。Pattern是日志内容的pattern,可以将request的属性打印到文件里,具体如何打印还得参看Tomcat官方文档。
 
上面的配置文件只提及到部分组件或标签,后面会介绍更多的配置信息。

深入浅出Tomcat/1- 来历和配置文件的更多相关文章

  1. 深入浅出Tomcat系列

    原本打算一篇文章就发了的,无奈文章太长,阅读压力较大.为了让阅读体验更好一些,还是分多篇吧,大概6篇. 下面是这个主题的目录: 深入浅出Tomcat/1- 来历和配置文件 深入浅出Tomcat/2 - ...

  2. 深入浅出Tomcat/4 - Tomcat容器

    Container是一个Tomcat容器的接口,Tomcat有四种容器 ·     Engine ·     Host ·     Context ·     Wrapper Engine代表整个Ca ...

  3. Tomcat服务器配置以及相关配置文件介绍

    摘自:http://blog.163.com/ny_lonely/blog/static/18892427320136925044357/ context.xml 文件   配置属性说明     用于 ...

  4. Tomcat相关目录及配置文件总结

    Tomcat根目录介绍      [bin]目录主要是用来存放tomcat的命令,主要有两大类,一类是以.sh结尾的(linux命令),另一类是以.bat结尾的(windows命令). 很多环境变量的 ...

  5. Tomcat 下4个配置文件详解

    Tomcat 的配置文件由4个 xml 文件构成,context.xml.web.xml.server.xml.tomcat-users.xml 这4个文件.每个文件都有自己的功能与配置方法,下列将逐 ...

  6. 深入浅出Tomcat/2 - Tomcat启动和停止

    Tomcat启动和停止 很明显,我们启动或停止Tomcat,一般调用的是bin下的startup.sh或shutdown.sh(以Linux为例,以下涉及到平台,若无特殊说明,一般都指Linux).我 ...

  7. tomcat 的 server.xml配置文件

    tomcat的配置文件在其安装后生成的conf目录下,其中主配置文件便是conf下的server.xml文件. server.xml文件由server->service->engine-& ...

  8. Tomcat相关目录及配置文件

    目录结构 [root@localhost tomcat]# tree -L 1.├── bin├── BUILDING.txt├── conf├── CONTRIBUTING.md├── lib├── ...

  9. 【Spring Boot】Spring Boot项目设置多个配置文件,并在生产环境中的Tomcat设置对应的配置文件

    1.修改Spring Boot项目配置文件 除了主配置文件,另外创建2个配置文件,注意命名要用application-*.properties 主配置文件中写入,使用dev作为开发配置 spring. ...

随机推荐

  1. 现有项目中集成Flutter

    本文列举了项目开发使用Flutter会遇到的问题,以及如何使用Flutter module在现有项目中集成Flutter,并对其原理进行了分析. 最近在做的一个商业项目,完全的使用Flutter编写的 ...

  2. git 入门教程之知识速查

    知识速查 创建版本库 初始化项目 git init 从零开始创建项目 示例 git init 克隆项目 git clone 将已有项目拷贝到本地 示例 git clone git@github.com ...

  3. 配置正确情况下,hadoop 没有namenode的一个解决方法

    将hdfs里name与data清空,和将tmp清空 然后在hadoop目录下运行 hadoop namenode -format 启动   sbin/start-all.sh

  4. [20190226]删除tab$记录的恢复6.txt

    [20190226]删除tab$记录的恢复6.txt --//春节前几天做了删除tan$记录的测试,链接:http://blog.itpub.net/267265/viewspace-2565245/ ...

  5. 虚拟机-linux系统中图形界面和命令行界面切换

    linux系统中图形化界面和命令行界面之间的切换可以分为两种,临时性切换和永久性切换. 临时性切换即切换后只对本次生效,系统重启后界面还是默认界面. 永久性切换即切换后系统开机后永远处于的界面. 临时 ...

  6. 关于getdate()的不同的日期格式

    在使用Sql Server查询数据库时,我们经常会需要查询日期格式的数据,对于日期在sql语言中的格式有一定的要求,通过修改convert中的最后一位参数,可以返回不通格式的时间,具体实现如下: Se ...

  7. c/c++ 图的创建(二维数组法)

    c/c++ 图的创建(二维数组法) 图的概念 图由点和线组成 知道了图中有多少个点,和哪些点之间有线,就可以把一张图描绘出来 点之间的线,分有方向和无方向 创建图 创建图,实际就是创建出节点,和节点之 ...

  8. UNIX高级环境编程(14)文件IO - O_DIRECT和O_SYNC详解 < 海棠花溪 >

    春天来了,除了工作学习,大家也要注意锻炼身体,多出去运动运动.  上周末在元大都遗址公园海棠花溪拍的海棠花.   进入正题. O_DIRECT和O_SYNC是系统调用open的flag参数.通过指定o ...

  9. burp抓取手机模拟器流量

    这里安装的是夜神模拟器,网络模式设置为桥接: 然后从burp suite 导出证书,存为.cer格式.将其导入手机模拟器(我用百度网盘导入的,自带的文件导入,不太会用,找不到放哪了) 然后给手机模拟器 ...

  10. C++借助curses库实现俄罗斯方块

    主要要实现如下几个功能:方块的移动控制.方块变形.判定方块是否接触边界和进行方块堆积.对方块进行消除. 1.方块的移动控制上下左右四个方向上-->变形,下-->加速下落,左-->向左 ...