Tomcat架构介绍及配置分析

文章目录
  1. 1. 1. conf/配置文件说明
    1. 1.1. 1.1 catalina.properties
    2. 1.2. 1.2 catalina.policy
    3. 1.3. 1.3 context.xml
    4. 1.4. 1.4 server.xml
    5. 1.5. 1.5 tomcat-users.xml
    6. 1.6. 1.6 web.xml
    7. 1.7. 1.7 loggin.properties
  2. 2. 2. 启动流程分析
    1. 2.1. 2.1 Idea调试Tomcat源码环境搭建
    2. 2.2. 2.2 Tomcat Server的组成
      1. 2.2.1. 2.2.1 整体说明
      2. 2.2.2. 2.2.2 各组件详解

在之前的项目中,需要对项目做集群,由于项目对系统的并发要求不大,所以就采取Session共享方式实现,虽然根据在网上找的资料完成了集群,但是对Tomcat的Session的共享的底层原理一直比较好奇,正好借此机会,调试一下Tomcat源码,略作分析。

  • bin

    存放启动和关闭Tomcat的脚本文件

  • conf

    存放Tomcat的各种配置文件

  • lib

    存放Tomcat的依赖jar包

  • logs

    存放Tomcat的日志文件

  • temp

    存放Tomcat运行中产生的临时文件

  • webapps

    web应用所在目录,即供外界访问的web资源的存放目录

  • work

    Tomcat的工作目录

1. conf/配置文件说明

1.1 catalina.properties

Tomcat的catalina.properties文件位于%CATALINA_HOME%/conf/目录下面,该文件主要配置tomcat的安全设置、类加载设置、不需要扫描的类设置、字符缓存设置四大块。

  • 安全设置

    1
    2
    package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat.
    package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.naming.,org.apache.tomcat.
  • 类加载设置

    tomcat的类加载顺序为:

    Bootstrap —> System —> /WEB-INF/classes —> /WEB-INF/lib/*.jar —> Common

    注: Common的配置是通过catalina.properties的commons.loader设置的

    1
    common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"

    类加载顺序:

    ${catalina.base}/lib 未打包的类和资源文件

    ${catalina.base}/lib/*.jar JAR文件

    ${catalina.home}/lib 未打包的类和文件

    ${catalina.home}/lib/*.jar JAR文件

    默认情况下,会加载以下内容:

    • annotations-api.jar — JavaEE注释类
    • catalina.jar — 执行Tomcat的Catalina Servlet容器部分
    • catalina-ant.jar — Tomcat Catalina Ant 任务
    • catalina-ha.jar — 高可用包
    • catalina-tribes.jar — 组通信包
    • ecj-\.jar* — Eclipse JDT Java 编译器
    • el-api.jar — EL 2.2 API.
    • jasper.jar — JSP 运行时编译器
    • jasper-el.jar — EL表达式的实现
    • jsp-api.jar — JSP 2.2 API.
    • servlet-api.jar — Servlet 3.0 API.
    • tomcat-api.jar — 由Tomcat定义的几个接口
    • tomcat-coyote.jar — Tomcat连接器和使用程序类
    • tomcat-dbcp.jar — 基于Apache Commons Pool和Apache Commons DBCP的数据库连接池
    • tomcat-i18n-**.jar — 包含其他语言的资源约束的可选JAR,默认捆绑包含在每个单独的应用中,如果不需要国际化,可以删除
    • tomcat-jdbc.jar — Tomcat JDBC数据库连接池
    • tomcat-util.jar — Tomcat的各种组件使用的常见类
    • tomcat7-websocket.jar — WebSocket 1.1 实现
    • websocket-api.jar — WebSocket 1.1 API

    注: CATALINA_HOME是Tomcat的安装目录,CATALINA_BASE是Tomcat的工作目录,一个Tomcat可以通过配置CATALINA_BASE来增加多个工作目录,也就是增加多个实例。多个实例各自可以有自己的conf,logs,temp,webapps。

    server.loader和shared.loader

    在common.loader加载完毕后,tomcat启动程序会检查catalina.properties文件中配置的server.loader和shared.loader是否设置。如果设置,读取tomcat下对应的server和shared这两个目录的类库。server和shared是对应tomcat目录下的两个目录,在Tomcat中默认是没有,catalina.properties中默认也是没有设置其值。设置方法如下:

    1
    2
    server.loader=${catalina.base}/server/classes,${catalina.base}/server/lib/*.jar
    shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar

    同时需要在tomcat目录下创建server和shared目录结构并将公用的、应用类放到里面。类加载顺序为:

    Bootstrap —> System —> /WEB-INF/classes —> /WEB-INF/lib/*.jar —> Common —> Server —> Shared

  • 字符缓存设置

    1
    2
    3
    4
    5
    # String cache configuration.
    tomcat.util.buf.StringCache.byte.enabled=true
    #tomcat.util.buf.StringCache.char.enabled=true
    #tomcat.util.buf.StringCache.trainThreshold=500000
    #tomcat.util.buf.StringCache.cacheSize=5000

总结: Tomcat可以通过catalina.properties的server和shared,为webapp提供公用类库。使一些公用的、不需要与webapp放在一起的设置信息单独保存,在更新webapp的war的时候无需更改webapp的设置。

1.2 catalina.policy

包含由Java Security Manager实现的安全策略声明,它替换了安装java时带有的java.policy文件。这个文件用来防止欺骗代码或JSP执行带有像System.exit(0)这样可能影响容器的破坏性代码,只有当Tomcat用-security命令行参数启动时这个文件才会被使用。

1.3 context.xml

这个通用context.xml可被所有的web应用程序使用,这个文件默认地可以设置到何处访问各web应用程序中的web.xml文件。context.xml文件的作用和server.xml中标签作用相同。在tomcat5.5之后,对Context的配置不推荐在server.xml中进行配置,而是在/conf/context.xml中进行独立的配置。因为server.xml是不可动态重加载的资源,服务器一旦启动了以后,要修改这个文件,就得重启服务器才能重新加载。而context.xml文件则不然,tomcat服务器会定时去扫描这个文件。一旦发现文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器。

默认的context.xml如下:

1
2
3
4
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>

以下给出一个JNDI数据源的配置:

1
2
3
4
5
6
7
8
9
10
11
<Resource name="jdbc/mysql"
auth="Container"
type="com.alibaba.druid.pool.DruidDataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"
/>

context.xml的作用范围

  • tomcat server级别

    在/conf/context.xml里配置

  • Host级别

    在/conf/Catalina/${hostName}里添加context.xml,继而进行配置。

  • web app级别

    在/conf/Catalina/\${hostName}里添加\${webappName}.xml,继而进行配置。

1.4 server.xml

tomcat的主要配置文件,解析器用这个文件在启动时根据规范创建容器。

默认的server.xml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<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>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<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是顶级元素,代表一个Tomcat实例。可以包含一个或多个Service,每个Service都有自己的Engines和Connectors。

Server元素

  • className

    使用Java实现类的名称。这个类必须实现org.apache.catalina.Server接口。如果没有指定类名,将会使用标准实现。

  • address

    server在这个TCP/IP地址上监听一个shutdown命令。如果没有指定地址,将会使用localhost。

  • port

    server在这个端口上监听一个shutdown命令。设置为-1表示禁用shutdown命令。

  • shutdown

    连接到指定端口的TCP/IP收到这个命令字符后,将会关闭Tomcat。

Listeners元素

Server可以包含多个监听器。一个监听器监听指定事件,并对其作出响应。

GlobalResourcesLifecycleListener作用于全局资源,保证JNDI对资源的可达性,比如数据库。

1
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  • SSLEngine

    使用的SSLEngine名称。off:不适用SSL,on:使用SSL但不指定引擎。默认值是on。会初始化本地SSL引擎,对于使用SSLEnabled属性的APR/native connector来讲,该选项必须可用。

  • SSLRandomSeed

    指定伪随机数生成器(PRNG)的随机数种子源,默认值为builtin。在开发环境下,可能要将其设置为/dev/urandom,以获得更快的启动速度。

  • FIPSMode

    设置为on会请求OpenSSL进入FIPS模式(如果OpenSSL已经处于FIPS模式,将会保留该模式)。该设置为enter会强制OpenSSl进入FIPS模式(如果OpenSSL已经处于FIPS模式,将会产生一个错误)。设置为require要求OpenSSL已经处于FIPS模式(如果OpenSSL当前没有处于FIPS模式将会产生一个错误)。

GlobalNamingResources元素全局命名资源

GlobalNamingResources元素定义了JNDI(Java命名和目录接口)资源,其允许Java软件客户端通过名称搜寻和查找数据。默认配置定义了一个名称为UserDatabase的JNDI,通过“conf/tomcat-users.xml”得到一个用于用户授权的内存数据库。

1
2
3
4
5
6
7
<GlobalNamingResources>
<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>

也可以定义其他全句话JNDI资源来实现连接池,比如MySQL数据库。

Services元素

一个Service可以连接一个或多个Connectors到一个引擎。默认配置定义了一个名为“Catalina”的Service,连接了两个Connectors:HTTP和AJP到当前的引擎。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<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>
  • className

    该实现使用的Java类名称。这个类必须实现org.apache.catalina.Service接口。如果没有指定类名称,将会使用标准实现。

  • name

    Service的显示名称,如果采用了标准的Catalina组件,将会包含日志信息。每个Service与某个特定的Server关联的名称必须是唯一的。

Connectors元素

一个Connector关联一个TCP端口,负责处理Service与客户端之间的交互。默认配置定义了两个Connectors。

  • HTTP/1.1

    处理HTTP请求,使得Tomcat成为一个HTTP服务器。客户端可以通过Connector向服务器发送HTTP请求,接收服务器端的HTTP响应信息。

    1
    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

    与生产服务默认使用80端口不同,Tomcat HTTP服务默认在TCP端口8080上运行。可以选择1024到65535之间的任意数字作为端口号来运行Tomcat服务器,前提是该端口没有被任何其他应用使用。connectionTimeOut属性定义了这个connector在链接获得同意之后,获得请求URI line(请求信息)响应的最大等待时间毫秒数。默认为20秒。redirect属性会把SSL请求重定向到TCP的8443端口。

  • AJP/1.3

    Apache JServ Protocol connector处理Tomcat服务器与Apache HTTP服务器之间的交互。

    1
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    可以将Tomcat和Apache HTTP服务运行在一起,Apache HTTP服务器处理静态请求和PHP;Tomcat服务器负责处理Java Servlet/JSP。

容器

包含了Engine、Host、Context和Cluster的Tomcat称为容器。最高级的是Engine,最底层的是Context。某些组件,比如Realm和Value,也可以放在容器中。

Engine引擎

引擎是容器中最高级别的部分。可以包含一个或多个Host。Tomcat服务器可以配置为运行在多个主机名上,包括虚拟主机。

1
<Engine name="Catalina" defaultHost="localhost">

Catalina引擎从HTTP connector接收HTTP请求,并根据请求头部信息中主机名或IP地址重定向到正确的主机上。

  • backgroundProcessorDelay

    这个值表示了在这个引擎和它的子容器上调用backgroundProcess方法之间间隔的秒数,包括所有host和context。值为非负时不会调用子容器(意味着其使用自身的处理线程)。设置为正值会产生一个衍生线程。等待指定的时间之后,该线程会在这个引擎和它的所有子容器上调用backgroundProcess方法。如果没有指定,默认值为10,即会有10秒的延迟。

  • className

    实现该引擎使用的Java类名。该类必须实现org.apache.catalina.Engine接口。如果没有指定,会使用标准值。

  • defaultHost

    默认主机名,定义了处理指向该服务器的请求所在主机的名称,但名称不是在这个文件中配置。

  • jvmRoute

    在负载均衡场景下必须定义该参数,来保证session affinity可用,对于集群中所有Tomcat服务器来讲定义的名称必须是唯一的,该名称将会被添加到生成的会话标示符中,因此,允许前端代理总是将特定会话转发到同一个Tomcat实例。

  • name

    Engine的逻辑名称,用在日志和错误信息中。当在相同的Server中使用多个Service元素时,每个Engine必须制定一个唯一的名称。

  • startStopThreads

    Engine在启动Host子元素时将会并发使用的线程数。如果设置为0,将会使用Runtime.getRuntime().availableProcessors()的值。设置为负数,将会使用Runtime.getRuntime().availableProcessors() + value的值,如果结果小于1,将会使用1个线程。如果没有指定,默认值为1。

Realm元素

一个Realm(域)就是一个包含user、password和role认证(比如访问控制)的数据库。你可以在任何容器中定义Realm,例如Engine、Host、Context和Cluster。

1
2
3
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>

默认配置定义了一个Catalina Engine的Realm(UserDatabaseRealm),对用户访问engine的权限进行控制。其使用定义在GlobalNamingResources中,名字为UserDatabase的JNDI。

除了UserDatabaseRealm以外,还有:JDBCRealm(授权用户是否可以通过JDBC驱动连接到关系型数据库);DataSourceRealm(通过JNDI连接到数据库);JNDIRealm(连接到一个LDAP目录);MemoryRealm(将XML文件加载到内存)。

  • className

    使用Java实现类的名称。这个类必须实现org.apache.catalina.Realm接口。

Hosts

一个Host定义了在Engine下的一个虚拟机,反过来其又支持多个Context(web应用)。

1
<Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">

默认配置定义了一个名为localhost的主机。appBase属性定义了所有webapp的根目录,在这种情况下是webapps。默认情况下,每一个webapp的URL和它所在的目录名称相同。例如,默认的Tomcat安装目录的webapps下提供了四个web应用:docs、examples、host-manager和manager。只有ROOT是个例外,它用一个空字符串定义。也就是说,它的URL是http://localhost:8080/。unpackWARs属性指定了放到webapps目录下的WAR-file是否应该被解压。对于unpackWARs=“false”,Tomcat将会直接从WAR-file运行应用,而不解压,这可能导致应用运行变慢。autoDeploy属性指定了是否自动部署放到webapps目录下的应用。

  • appBase

    虚拟机应用的根目录。该目录是一个可能包含部署到虚拟机上web应用的路径名。也可能是一个指定的绝对路径名,或者是一个相对于$CATALINA_BASE目录的路径名。如果没有指定,默认会使用webapps。

  • xmlBase

    虚拟机XML根目录。该目录是一个可能包含部署到虚拟机上context XML描述符的路径名。也可能是一个指定的绝对路径名,或者是一个相对于$CATALINA_BASE目录的路径名。如果没有指定,默认会使用conf/目录。

  • createDirs

    如果设置为true,Tomcat将会在启动阶段,尝试创建一个由appBase和xmlBase属性定义的目录。默认值为true。如果设置为true,并且目录创建失败,将会打印出一个错误信息,但是不会终止启动过程。

  • autoDeploy

    该属性的值指明了在Tomcat运行的时候,是否需要定义检查新的或者更新后的web应用。如果为true,Tomcat会定义检查appBase和xmlBase目录,并对找到的新web应用和context XML描述符进行部署。更新web应用或XML上下文描述符将会触发web应用的重载。默认值为true。

  • backgroundProcessorDeploy

    表示在调用这台主机的backgroundProcess方法和它的子容器方法,包括所有的context,之间延迟的秒数。如果延迟值不是负数的话,不会调用子容器(意味着会使用它们自己的处理线程)。设置为正数会产生衍生线程。在等待指定的时间之后,线程将会在该host上调用backgroundProcess方法,包括它的所有子容器。host将会使用后台进程执行web应用部署相关的任务。如果没有指定,默认值为-1,意味着host将会依赖于它的父引擎的后台处理线程。

  • className

    使用的Java实现类的名称。该类必须实现org.apache.catalina.Host接口。

  • deployIgnore

    一个正则表达式,定义了在自动部署和启动时部署的情况下需要忽略的目录。这就允许我们在版本控制系统中保持自己的配置,例如,不会将.svn或者git文件夹部署到appBase目录下。该正则表达式是相对于appBase的。同时也是固定的,意味着是相对于整个文件或目录的名称进行的。因此,foo只会匹配名称为foo的文件或目录,而不会匹配foo.war等名称的文件或目录。如果想让“foo”匹配任意名称,可以使用“.*foo.*”。

  • deployOnStartup

    指定在Tomcat启动时是否需要自动部署host下的web应用。默认值为true。

  • failCtxlfServletStartFails

    设置为true时,如果它的任意一个load-on-startup >= 0的servlet停止自身启动后,停止启动它的每一个子context。每一个子context可能覆盖这个属性。如果没有指定,将会使用默认值false。

  • name

    通常是虚拟主机的网络名称,注册在你的域名服务器上。无论指定的主机名称是什么样的,Tomcat在内部都会将其转换为小写。嵌套在Engine内部的Host,其中必须有一个Host的名称匹配Engine的默认Host设置。

  • startStopThreads

    Host在启动子Context元素时会并发使用的线程数。如果自动部署被使用的话将会使用该线程池部署新的Context。值为0时将会使用Runtime.getRuntime().availableProcessors()的值。值为负数时将会使用Runtime.getRuntime().availableProcessors()加上该值得和,小于1时将会使用1个线程。如果没有指定,会使用默认值1。

  • undeployOldVersion

    该选项的值决定Tomcat,即自动部署进程部分,是否会检查并发部署的过时web应用,任何找到的应用都会被移除。只有在autoDeploy为true的情况下才会生效。如果没有指定将会使用默认值false。

Value

Value(阀门)作为请求的前置处理程序,可以在请求发送到应用之前拦截HTTP请求。可以定义在任何容器中,比如Engine、Host、Context和Cluster。默认配置中,AccessLogValue会拦截HTTP请求,并在日志文件中创建一个切入点

1
2
3
<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" />
  • className

    设置为org.apache.catalina.ha.tcp.ReplicationValue

  • filter

    对于已知文件扩展名或url,可以在请求中使用Value通知cluster没有修改session,对于本次变化cluster没有必要通知session管理者。如果请求匹配该过滤器模型,cluster会假设session没有发生变化。一个filter样例大概是这样的filter=“.*.gif|.*.js|.*.jpeg|.*.jpg|.*.png|.*.htm|.*.html|.*.css|.*.txt”。filter使用java.util.regex的正则表达式。

  • primaryIndicator

    布尔值,如果为true,replication value将会把primaryIndicatorName属性定义的名称插入到request属性中,该值无论是Boolean.TRUE或者Boolean.FALSE,都会被放入request属性中。

  • primaryIndicatorName

    默认值为org.apache.catalina.ha.tcp.isPrimarySession,这个值定义了一个request属性的名称,值是一个布尔值,表示会话所在的服务器是否为主服务器。

  • statistics

    布尔值,如果想让value手机请求的统计数据,设置为true,默认值为false。

  • RemoteAddrValue

    阻截来自特定IP地址的请求。

  • RemoteHostValue

    阻截基于主机名称的请求。

  • RequestDumperValue

    记录了请求的详细信息。

  • SingleSignOnValue

    当置于a下时,允许单点登录到该主机下的所有应用上。

1.5 tomcat-users.xml

用于访问tomcat管理应用程序时的安全性设置,用server.xml中引用的默认的用户数据库域(UserDatabase Realm)使用它,所有的凭证默认都是被注释的,如需授权和访问控制,或配置角色,可参考以下配置。

1
2
3
4
5
<role rolename="manager"/>
<role rolename="manager-gui"/>
<role rolename="admin"/>
<role rolename="admin-gui"/>
<user username="admin" password="admin" roles="admin-gui,admin,manager-gui,manager"/>

这样tomcat7首页上的Server Status、Manager App、Host Manager就都可以点击登录进去。

tomcat6配置:

1
2
3
<role rolename="admin"/>
<role rolename="manager"/>
<user username="admin" password="admin" roles="admin,manager"/>

1.6 web.xml

默认的web.xml文件可被所有的web应用程序使用,这个web.xml文件会设置jspservlet以支持应用程序处理jsps,并设置一个默认的servlet来处理静态资源和html文件,它还设置默认的回话超时以及像index.jsp,index.html这类欢迎文件,并且它为最通用的扩展文件设置默认的MIME类型。

一般在Java工程中,web.xml用来初始化工程配置信息,比如welcome页面,filter,listener,servlet,servlet-mapping,启动加载级别等等。

当应用程序被部署到tomcat时,它会用[engine name]/[host name]/[context-path name].xml创建与context.xml等效的文件,如用户也在\$CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default文件,在这个文件中特定主机下的所有web应用程序将对主机器虚拟环境采用一系列默认设置。

下面就详细介绍一下web.xml中常用的标签及其功能。

\<description>,\<display-name>,\<icon>

  • \<description>

    1
    <description>项目描述</description> <!--对项目作出描述-->
  • \<display-name>

    1
    <display-name>项目名称</display-name> <!--定义项目的名称-->
  • \<icon>及\<small-icon>,\<large-icon>

    \<icon> icon元素包含small-icon和large-icon两个子元素,用来指定web站台中小图标和大图标的路径。

    1
    2
    3
    4
    <!--small-icon元素应指向web站台中某个小图标的路径,大小为16X 16 pixel,但是图像文件必须为GIF或JPEG格式,扩展名必须为.git或.jpg-->
    <small-icon>/路径/smallicon.gif</small-icon>
    <!--large-icon元素应指向web站台中某个大图标路径,大小为32X 32pixel,但是图像文件必须为GIF或JPEG的格式,扩展名必须为.git或.jpg-->
    <large-icon>/路径/largeicon.jpg</large-icon>

    例如:

    1
    2
    3
    4
    5
    6
    <display-name>Demo Example</display-name>
    <description>JSP 2.0 Demo Example</description>
    <icon>
    <small-icon>/images/small.gif</small-icon>
    <large-icon>/images/large.gif</large-icon>
    </icon>

\<context-param>

\<context-param>元素含有一对参数名和参数值,用作应用的servlet上下文初始化参数。参数名在整个web应用中必须是唯一的。

例如:

1
2
3
4
<context-param>
<param-name>name</param-name>
<param-value>haha</param-value>
</context-param>

此处设定的参数,在JSP页面可以使用\${initParam.name}来获取。

在Servlet中可以使用下列方式获取:

1
String name = getServletContext().getInitParamter("name");

\<filter>

filter元素用于指定web容器中的过滤器。

在请求和响应对象被servlet处理之前或之后,可以使用过滤器对这两个对象进行操作。通过filter-mapping元素,过滤器被映射到一个servlet或一个URL模式。这个过滤器的filter元素和filter-mapping元素必须具有相同的名称。

filter元素用来声明filter的相关设定,filter元素除了下面介绍的子元素之外,还包括<icon>,\<display-name>,\<description>,\<init-param>,其用途一样。

例如:

1
2
3
4
5
6
7
8
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>

\<filter-mapping>

filter-mapping元素用来声明web应用中的过滤器映射。过滤器可被映射到一个servlet或一个URL模式。将过滤器映射到一个servlet中会造成过滤器作用于servlet上。将过滤器映射到一个URL模式中则可以将过滤器应用于任何资源,只要该资源的URL与URL模式匹配。过滤是按照部署描述符的filter-mapping元素出现的顺序执行的。

filter-mapping元素的两个主要子元素filter-name和url-pattern用来定义Filter对应的URL。还有servlet-name和dispatcher子元素,不是很常用。

特别说明一下dispatcher,设置Filter对应的请求方式,有:REQUEST,INCLUDE,FORWAR,ERROR四种,默认为REQUEST。

例如:

1
2
3
4
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

\<servlet>

在web.xml中完成一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称,使用servlet-mapping元素将定制的URL与刚分配的名称相关联。

例如:

1
2
3
4
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

\<servlet-mapping>

servlet-mapping元素包含两个子元素servlet-name和url-pattern,用来定义servlet所对应的URL。

例如:

1
2
3
4
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

\<listener>

listener元素用来注册一个监听器类,可以在web应用中包含该类。使用listener元素,可以收到事件什么时候发生以及用什么作为响应的通知。

listener元素用来定义Listener接口,它的主要子元素为\<listener-class>

例如:

1
2
3
<listener>
<listener-class>com.gnd.web.listener.TestListener</listener-class>
</listener>

\<session-config>

session-config包含一个子元素session-timeout,定义web应用中session的有效期限。

例如:

1
2
3
<session-config>
<session-timeout>900</session-timeout>
</session-config>

\<mime-mapping>

mime-mapping包含两个子元素extension和mime-type,定义某个扩展名和某一MIME Type做对应。

\<extension>扩展名名称\</extension>

\<mime-type>MIME格式\</mime-type>

例如:

1
2
3
4
5
6
7
8
9
10
11
12
<mime-mapping>
<extension>doc</extension>
<mime-type>application/vnd.ms-word</mime-type>
</mime-mapping>
<mime-mapping>
<extension>xls</extension>
<mime-type>application/vnd.ms-excel</mime-type>
</mime-mapping>
<mime-mapping>
<extension>ppt</extension>
<mime-type>application/vnd.ms-powerpoint</mime-type>
</mime-mapping>

\<welcome-file-list>

welcome-file-list包含一个子元素welcome-file,用来定义首页列表。

welcome-file用来指定首页文件名称,服务器会按照设定的顺序来找首页。

例如:

1
2
3
4
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

\<error-page>

error-page元素包含三个子元素error-code,exception-type和location。

将错误代码后异常的种类对应到web应用资源路径。

例如:

1
2
3
4
5
6
7
8
<error-page>
<error-code>404</error-code>
<location>error404.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>error404.jsp</location>
</error-page>

\<jsp-config>

jsp-config元素主要用来设定jsp的相关配置,jsp-config包括taglib和jsp-property-group两个子元素,其中taglib元素在JSP1.2时就已经存在,而jsp-property-group是JSP2.0新增的元素。

\<taglib>

taglib元素包含两个子元素taglib-uri和taglib-location,用来设定JSP网页用到的TagLibrary路径。

\<taglib-uri>URI\</taglib-uri>

taglib-uri定义TLD文件的URI,JSP网页的taglib指令可以经由这个URI存取到TLD文件。

\<taglib-location>/WEB-INF/lib/xxx.tld\</taglib-location>

TLD文件对应web应用的存放位置。

\<jsp-property-group>

jsp-property-group元素包含8个子元素,分别为:

\<description>Description\</description> 此设定的说明

\<display-name>Name\</display-name> 此设定的名称

\<url-pattern>URL\</url-pattern> 设定值所影响的范围,如*.jsp

\true/false\</el-ignored> 是否支持EL语法

\<scripting-invalid>true/false\</scripting-invalid> 是否支持java代码片段<%…%>

\<page-encoding>UTF-8\</page-encoding> 设置JSP页面的编码

\<include-prelude>.jspf\</include-prelude> 设置JSP页面的抬头,扩展名为.jspf

\.jspf\ 设置JSP页面的结尾,扩展名为.jspf

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<jsp-config>
<taglib>
<taglib-uri>Taglib</taglib-uri>
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>
<jsp-property-group>
<description>Configuration JSP example</description>
<display-name>JspConfig</display-name>
<url-pattern>/*</url-pattern>
<el-ignored>true</el-ignored>
<page-encoding>UTF-8</page-encoding>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>

\<resource-ref>

resource-ref元素包含五个子元素description,res-ref-name,res-type,res-auth,res-sharing-scope,利用JNDI取得应用可利用资源。

\<res-auth>Application/Container\</res-auth> 资源由Application或Container来许可。

\Shareable|Unshareable\ 资源是否可以共享,默认值为Shareable

例如:

1
2
3
4
5
<resource-ref>
<res-ref-name>jdbc/Druid</res-ref-name>
<res-type>com.alibaba.druid.pool.DruidDataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

1.7 loggin.properties

JULI记录器使用默认日志配置,它默认地使用ConsoleHandler和fileHandler设置应用程序或者程序包的日志级别。

2. 启动流程分析

2.1 Idea调试Tomcat源码环境搭建

首先下载Tomcat源码,读者可自行去Tomcat官网 下载,若执行力差的同学也可直接从此处pull。

Tomcat源码导入到开发工具中的方法有多种,笔者采用最直接的方式,解压源码包后直接导入到开发工具中,导入之后的源码并不能直接运行,还需要几个依赖包,读者可从此处的lib目录下获取,也可自行搜集。

找好依赖包也并不能让Tomcat源码正常运行,还需要为Bootstrap这个启动类增加几个启动参数。

1
2
3
4
5
6
-Dcatalina.home=/Users/chenmin/GitHub/tomcat
-Dcatalina.base=/Users/chenmin/GitHub/tomcat
-Djava.endorsed.dirs=/Users/chenmin/GitHub/tomcat/endorsed
-Djava.io.tmpdir=/Users/chenmin/GitHub/tomcat/temp
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=/Users/chenmin/GitHub/tomcat/conf/logging.properties

上面的参数具体代表的意思就不一一详述了,其实光看名字就知道都是干嘛用的了。

以上准备步骤做好之后,就可以直接运行Bootstrap类,运行Tomcat源码进行调试了。

2.2 Tomcat Server的组成

2.2.1 整体说明

在上面对配置文件的说明中,通过server.xml的解释,我们知道server.xml中最顶级的元素是server,而server.xml中的每一个元素我们都可以把它看做是Tomcat中的某一个部分。所以我们可以参照着server.xml来分析源码。

Tomcat最顶层的容器叫Server,它代表着整个Tomcat服务器。Server中至少要包含一个Service来提供服务。Service包含两部分:Connector和Container。Connector负责网络连接,request/response的创建,并对Socket和request、response进行转换等,Container用于封装和管理Servlet,并处理具体的request请求。

一个Tomcat中只有一个Server,一个Server可以有多个Service来提供服务,一个Service只有一个Container,但是可以有多个Connector(一个服务可以有多个连接)。

tomcat整体结构

2.2.2 各组件详解

可结合conf/配置文件说明中的server.xml的说明来看

  • Server

    Server代表整个Servlet容器

  • Service

    Service是由一个或多个Connector以及一个Engine,负责处理所有Connector所获得的客户请求的集合。

  • Connector

    Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回给客户端。

    Tomcat有两个默认的Connector,一个直接监听来自浏览器的http请求,一个监听来自其他WebServer的请求。

    Coyote Http/1.1 Connector在端口8080上监听来自浏览器的http请求

    Coyote AJP/1.3 Connector在端口8009上监听来自其他WebServer的servlet/jsp代理请求。

  • Engine

    Engine下可以配置多个虚拟主机,每个虚拟主机都有一个域名,当Engine获得一个请求时,Engine会把该请求匹配到某个Host上,然后把该请求交给该Host来处理。

    Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理。

  • Host

    代表一个虚拟主机,每个虚拟主机和某个网络域名相匹配。每个虚拟主机下都可以部署一个或者多个WebApp,每个WebApp对应于一个Context,有一个ContextPath。当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理。匹配的方法是“最长匹配”,所以一个path==“”的Context将成为该Host的默认Context,所有无法和其他Context的路径名匹配的请求都将最终和该默认Context匹配。

  • Context

    一个Context对应于一个Web Application(Web应用),一个Web应用有一个或多个Servlet组成,Context在创建的时候将根据配置文件\$CATALINA_HOME/conf/web.xml和\$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。如果找到,则执行该类,获得请求的回应,并返回。

    Tomcat各组件关系图(此图来此网上)

    QQ截图20170913174040

如果文章对你有帮助,欢迎点击上方按钮打赏作者