Apache Tomcat 是一款非常著名的开源 Servlet/JSP 容器。
原文:http://www.solol.org/technologic/java/j-tomcatarch/
Apache Tomcat 是一款非常著名的开源 Servlet/JSP 容器,被用做 Java Servlet 和 JavaServer Pages 技术的官方参考实现。如果您要了解这两种技术的细节可以查阅参考资料。
让我们先来浏览一下 Tomcat 体系结构中的六个主要概念:
由
于Tomcat体系结构的内容非常丰富,所以本文非常长。因此我们尽量的使每一部分尽可能自成一体,使您可以独立阅读。如果您不是想全面了解Tomcat
的体系结构,只是想解决某一部分的具体问题,那么我们建议您使用目录导航到相关的内容,而不必在其它的内容上花费宝贵的时间。
Server代表整个容器(container)。它可以包含一个或多个Service,还可以包含一个GlobalNamingResources。
值
得注意的是在标准的Server接口中没有包括Lifecycle接口,但是在标准实现
org.apache.catalina.core.StandardServer中却实现了Lifecycle这个接口,这使得我们可以为Tomcat
的标准实现设置Listener。一般的方法是在conf/server.xml文件中加入:
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.solol.listener.XXXLifecycleListener" />
<Listener className="org.solol.listener.XXXLifecycleListener" />
:
:
:
</Server>
其中的XXXLifecycleListener为您自定义的LifecycleListener,而且必须要实现LifecycleListener接口。您可以在这里设置多个LifecycleListener,但要使用不同的名字。
由于在Tomcat的官方文档中没有显著的说明,所以这种使用Listener的方式没有体现在稍后给出的 体系结构图 中。
Server支持className,port和shutdown三个公共属性,而标准实现org.apache.catalina.core.StandardServer还可能支持一些扩展属性。详细的内容您可以查阅这里。
您可以通过稍后给出的 体系结构图 了解在整个Tomcat体系结构中Server所处的位置。
Service中可以含有一个或多个Connector,但只能含有一个Engine。这使得不同的Connector可以共享同一个Engine。同一个Server中的多个Service之间没有相关性。
值
得注意的是在标准的Service接口中没有包括Lifecycle接口,但是在标准实现
org.apache.catalina.core.StandardService中却实现了Lifecycle这个接口,这使得我们可以为
Tomcat的标准实现设置Listener。
由于在Tomcat的官方文档中没有显著的说明,所以这种使用Listener的方式没有体现在稍后给出的 体系结构图 中。
Service支持className和name两个公共属性,而标准实现org.apache.catalina.core.StandardService还可能支持一些扩展属性。详细的内容您可以查阅这里。
您可以通过稍后给出的 体系结构图 了解在整个Tomcat体系结构中Service所处的位置。
Engine负责接收和处理来自它所属的Service中的所有Connector的请求。
Engine
支持backgroundProcessorDelay、className、defaultHost、jvmRoute和name五个公共属性,而标准
实现org.apache.catalina.core.StandardEngine还可能支持一些扩展属性。详细的内容您可以查阅这里。
您可以通过稍后给出的 体系结构图 了解在整个Tomcat体系结构中Engine所处的位置。
从图中可以看出Engine右边有四个不同颜色的小方块,它们表示Engine所支持的四个不同的特性。相同颜色的小方块可能也会出现在其它的地方,这表示在那里也支持相同的或相似的特性。每种特性的具体描述可以在文中的Special Features中找到。
从图中可以看出Engine下边有一个红色的圆角矩形,它们表示Engine所支持的一个内嵌组件。相同颜色的圆角矩形可能也会出现在其它的地方,这表示在那里也支持相同的或相似的内嵌组件。每种内嵌组件的具体描述可以在文中的Nested Components中找到。
Host表示一个虚拟主机,并和一个服务器的网络名关联。注意Engine中必须有一个Host的名字和Engine的defaultHost属性匹配。
有时候,网络管理员可能希望将多个网络名关联到一个虚拟主机,这可以通过下文介绍的Host Name Aliases特性完成。
Host
支持appBase、autoDeploy、backgroundProcessorDelay、className、deployOnStartup和
name六个公共属性,而标准实现org.apache.catalina.core.StandardHost还可能支持一些扩展属性。详细的内容您可
以查阅这里。
您可以通过稍后给出的 体系结构图 了解在整个Tomcat体系结构中Host所处的位置。
从图中可以看出Host右边有八个不同颜色的小方块,它们表示Host所支持的八个不同的特性。相同颜色的小方块可能也会出现在其它的地方,这表示在那里也支持相同的或相似的特性。每种特性的具体描述可以在文中的Special Features中找到。
从图中可以看出Host下边有一个红色的圆角矩形,它们表示Host所支持的一个内嵌组件。相同颜色的圆角矩形可能也会出现在其它的地方,这表示在那里也支持相同的或相似的内嵌组件。每种内嵌组件的具体描述可以在文中的Nested Components中找到。
Connector负责接收来自客户端(Client)的请求。比较常见的两个是HTTP Connector和AJP Connector。
您可以通过稍后给出的 体系结构图 了解在整个Tomcat体系结构中Connector所处的位置。
Context表示在虚拟主机中运行的web应用程序。一个虚拟主机中能够运行多个Context,它们通过各自的Context Path进行相互区分。如果Context Path为"",那么该web应用为该虚拟主机的默认的web应用。
目前可以通过四种方式将Context加入Host:
- $CATALINA_HOME/conf/context.xml,其中Context元素中的信息会被所有web应用程序加载
- $CATALINA_HOME/conf/[enginename]/[hostname]/context.xml.default,其中Context元素中的信息会被hostname主机下的所有web应用程序加载
- $CATALINA_HOME/conf/[enginename]/[hostname]/目录中所有以.xml为扩展名的文件,其中Context元素中的信息会被hostname主机下的所有web应用程序加载
- 如果通过上面的步骤没有找到,那么最后要从web应用程序的/META-INF/context.xml目录中查找
Context
支持backgroundProcessorDelay、className、cookies、crossContext、docBase、
override、privileged、path、reloadable和wrapperClass十个公共属性,而标准实现
org.apache.catalina.core.StandardContext还可能支持一些扩展属性。详细的内容您可以查阅这里。
您可以通过稍后给出的 体系结构图 了解在整个Tomcat体系结构中Context所处的位置。
从图中可以看出Context右边有十个不同颜色的小方块,它们表示Context所支持的十个不同的特性。相同颜色的小方块可能也会出现在其它的地方,这表示在那里也支持相同的或相似的特性。每种特性的具体描述可以在文中的Special Features中找到。
从
图中可以看出Context下边有五个不同颜色的圆角矩形,它们表示Context所支持的五个内嵌组件。相同颜色的圆角矩形可能也会出现在其它的地方,
这表示在那里也支持相同的或相似的内嵌组件。每种内嵌组件的具体描述可以在文中的Nested Components中找到。
Tomcat 的体系结构图
GlobalNamingResources 组件为 Server 定义全局 JNDI 资源。这些资源出现在 Server 的全局 JNDI 资源上下文中。这个上下文和每个 web 应用程序的 JNDI 上下文不同。在全局 JNDI 上下文中定义的资源在每个
web 应用程序的 JNDI 上下文中不可见,但是可以通过 Resource Links 来改变这种可见性。如果您要了解在 Tomcat 中如何使用 JNDI 资源可以查阅参考资料。
从前面给出的 体系结构图
中可以看出GlobalNamingResources右边有四个不同颜色的小方块,它们表示GlobalNamingResources所支持的四个不
同的特性。相同颜色的小方块可能也会出现在其它的地方,这表示在那里也支持相同的或相似的特性。每种特性的具体描述可以在文中的Special
Features中找到。
从前面给出的 体系结构图 中可以看出,Realm组件在Engine、Host和Context中都有支持。
Realm
是一个"数据库"存储着用户名、密码和角色信息。通过自定义Realm可以将Catalina集成到其它的环境。Engine、Host和Context
中的Realm可以被较低级别的容器继承,即Host继承Engine的Realm,Context继承Host的Realm,除非我们显示的禁止这种继
承。
Realm支持className一个公共属性。Tomcat提供了多个实现:
- org.apache.catalina.realm.JDBCRealm
- org.apache.catalina.realm.DataSourceRealm
- org.apache.catalina.realm.JNDIRealm
- org.apache.catalina.realm.MemoryRealm
如果您要了解这些Realm的更多信息,可以查阅这里。
如果您要了解这些Realm的更多的设置信息,可以查阅参考资料。
从前面给出的 体系结构图 中可以看出,Loader组件只在Context中都有支持。
Loader是web应用程序的类装载器。必须有一个类装载器按照Servlet Specification的要求从如下的位置装载类:
- 从web应用程序的/WEB-INF/classes目录装载
- 从web应用程序的/WEB-INF/lib目录中的jar文件中装载
- 从Catalina中装载对于所有web应用可见的资源
Loader元素应该嵌入到Context元素中,如果没有设置那么会自动创建一个默认的Loader。如果想更深入的了解Catalina实现的Loader可以查阅参考资料。
Loader支持className、delegate和reloadable三个公共属性,而标准实现org.apache.catalina.loader.WebappLoader还可能支持一些扩展属性。详细的内容您可以查阅这里。
从前面给出的 体系结构图 中可以看出,Manager组件只在Context中有支持。
Manager是session管理器(session manager),负责session的创建和维护。
Manager元素应该嵌入到Context元素中,如果没有设置那么会自动创建一个默认的Manager。
Manager
支持className和distributable两个公共属性,而标准实现
org.apache.catalina.session.StandardManager和
org.apache.catalina.session.PersistentManager还可能支持一些扩展属性。详细的内容您可以查阅这里。
从前面给出的 体系结构图 中可以看出,Resources组件只在Context中有支持。
Resources表示web应用程序的静态资源。这使得我们有可能实现non-filesystem based Resources。如果想更深入的了解可以查阅参考资料
Resources元素应该嵌入到Context元素中,如果没有设置那么会自动创建一个默认的基于文件系统的Resources。
Resources支持className一个公共属性,而标准实现org.apache.naming.resources.FileDirContext还可能支持一些扩展属性。详细的内容您可以查阅这里。
从前面给出的 体系结构图 中可以看出,WatchedResource组件只在Context中都有支持。
WatchedResource用来告知Auto Deployer那些静态资源的更新需要被监控。如果被监控的资源被更新了那么该资源所对应的web应用将会被重新装载。这个元素的内容必须是一个String。
从前面给出的 体系结构图 中可以看出,Logging特性在Engine、Host和Context中都有支持。这个特性使得我们可以区分日志记录的具体来源。
在Engine、Host和Context中的日志类别分别为:
org.apache.catalina.core.ContainerBase.[enginename]
org.apache.catalina.core.ContainerBase.[enginename].[hostname]
org.apache.catalina.core.ContainerBase.[enginename].[hostname].[path]
其中中括号([])中为具体的名称。
Logging特性的实现是通过org.apache.catalina.core.ContainerBase来完成的。
从前面给出的 体系结构图 中可以看出,Access Logs特性在Engine、Host和Context中都有支持。
- Engine中的Access Logs记录所有Engine处理的请求的访问日志
- Host中的Access Logs记录所有Host处理的请求的访问日志
- Context中的Access Logs记录所有Context处理的请求的访问日志
一般的配置方法是在conf/server.xml文件的相关元素中加入:
<Engine ...>
...
<Valve className="org.apache.catalina.valves.AccessLogValve"
prefix="catalina_access_log." suffix=".txt" pattern="common"/>
...
</Engine>
上面的<Engine>,在Host中要被换成<Host>,在Context中要被换成<Context>。
Access Logs特性的实现是通过Tomcat的Value框架来完成的。如果您要了解这种技术的细节可以查阅参考资料。
如果您要了解Access Log Valve设置的更多信息,可以查阅这里。
从前面给出的 体系结构图 中可以看出,Lifecycle Listeners特性在Engine、Host和Context中都有支持。这个特性使得我们可以方便的进行生命周期的管理。
值得一提的是在Tomcat的标准实现中Server和Service也支持生命周期的管理,但是在官方文档中没有显著的说明,所以没有在图中体现出来。细节可以查阅Server和Service部分。
- Engine中的Lifecycle Listeners监听该Engine的生命周期事件(Eifecycle Event)
- Host中的Lifecycle Listeners监听该Host的生命周期事件(Eifecycle Event)
- Context中的Lifecycle Listeners监听该Context的生命周期事件(Eifecycle Event)
一般的配置方法是在conf/server.xml文件的相关元素中加入:
<Engine ...>
...
<Listener className="com.mycompany.mypackage.MyListener" ... >
...
</Engine>
上面的<Engine>,在Host中要被换成<Host>,在Context中要被换成<Context>。
另外,可以通过<Listener>元素为listener添加属性。
注意和Container Event区别。
从前面给出的 体系结构图 中可以看出,Request Filters特性在Engine、Host和Context中都有支持。
- Engine中的Request Filters过滤所有Engine处理的请求
- Host中的Request Filters过滤所有Host处理的请求
- Context中的Request Filters过滤所有Context处理的请求
一般的配置方法是在conf/server.xml文件的相关元素中加入:
<Engine ...>
...
<Valve className="org.apache.catalina.valves.RemoteHostValve"
allow="*.mycompany.com,www.yourcompany.com"/>
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
deny="192.168.1.*"/>
...
</Engine/>
上面的<Engine>,在Host中要被换成<Host>,在Context中要被换成<Context>。
Request Filters特性的实现是通过Tomcat的Value框架来完成的。如果您要了解这种技术的细节可以查阅参考资料。
如果您要了解Remote Address Filter设置的更多信息,可以查阅这里。
如果您要了解Remote Host Filter设置的更多信息,可以查阅这里。
从前面给出的 体系结构图 中可以看出,Automatic Application Deployment特性只在Host中都有支持。
如果使用Host的标准实现,同时deployOnStartup属性值为true(这是默认值),那么Catalina在首次启动时会自动完成下面的工作:
- $CATALINA_HOME/conf/[engine_name]/[host_name]目录下的所有XML文件都被假定含有<Context>元素。
- appBase
目录下的所有没有展开的war文件(没有展开的意思是没有和war文件名不包括.war扩展名对应的目录存在)会被自动展开,除非unpackWARs属
性值为false。如果重新部署更新的war文件,在重起Tomcat之前要删除先前展开的目录(如果autoDeploy属性值为true那么只要删除
先前展开的目录更新后的war文件就会自动展开)。
- 对
于appBase中含有/WEB-INF/web.xml文件的任何子目录都会自动产生一个Context,不管该子目录是否在conf
/server.xml文件中出现过。这个新产生的Context将会根据DefaultContext的属性值进行设置,其context
path为“/目录名”。如果目录名为ROOT,那么context path为“”。
因此要使用上面的规则需要将XML设置文件拷贝到$CATALINA_HOME/conf/[engine_name]/[host_name]目录下或将war文件和含有web应用的目录拷贝到appBase目录下。
自动部署(Auto Deployer)也会跟踪如下web应用程序的变化:
- 更新WEB-INF/web.xml文件将会使web应用程序重新加载
- 更新已展开的war文件会使web应用程序卸载(undeploy)(同时移除先前展开的目录)并重新部署(deployment)
- 更新XML设置文件会使web应用程序卸载(undeploy)(不移除任何展开的目录)并重新部署(deployment)
在使用自动部署的时候XML设置文件中的docBase要指向appBase目录之外。否则部署将很困难或应用程序会被部署两次。
如果要显示的定义context,那么需要关闭自动部署。否则相应的context将会部署两次,这可能会有问题。
从前面给出的 体系结构图 中可以看出,Host Name Aliases特性只在Host中都有支持。
在一些时候,网络管理员会将多个网络名(在DNS服务器中)解析到同一个服务器。通常每一个网络名会对应到一个Host。不过有时候需要将多个网络名对应到一个Host,Host Name Aliases用来完成这个目标。
一般的配置方法是在conf/server.xml文件的相关元素中加入:
<Host name="www.mycompany.com" ...>
...
<Alias>mycompany.com</Alias>
...
</Host>
<Host>元素中可以嵌入一个或多个<Alias>元素。
从前面给出的 体系结构图 中可以看出,Single Sign On特性只在Host中都有支持。
在一些时候,特别是在Portal环境下,可能会希望当用户访问一个虚拟主机下的多个web应用时只登陆一次,即所谓的单点登陆。
一般的配置方法是在conf/server.xml文件的相关元素中加入:
<Host name="localhost" ...>
...
<Valve className="org.apache.catalina.authenticator.SingleSignOn"
debug="0"/>
...
</Host>
Single Sign On操作遵循下面的规则:
- 该虚拟主机下的所有Web应用程序必须共享同一个Realm。在实践中通常通过为Host或(对应的Engine)嵌入Realm而不是为每一个Context嵌入相同的Realm来实现。
- 在用户访问该虚拟主机下的所有Web应用程序中的非保护资源时不需要验证。
- 在用户访问该虚拟主机下的所有Web应用程序中的保护资源时需要验证。
- 一旦被验证,就会对该虚拟主机下的所有Web应用程序有效,而不用每个应用程序单独验证。
- 如果用户从一个Web应用中退出,那么所有Web应用程序中的session都会失效。
- 使用SSO需要客户环境支持cookies。
Single Sign On特性的实现是通过Tomcat的Value框架来完成的。如果您要了解这种技术的细节可以查阅参考资料。
如果您要了解Single Sign On设置的更多信息,可以查阅这里。
从前面给出的 体系结构图 中可以看出,User Web Applications特性只在Host中都有支持。
许多Web服务器都可以处理如下形式的请求:
http://www.mycompany.com:8080/~craigmcc
其中craigmcc为系统的一位用户名。具体的处理过程和操作系统相关。
在类Unix或Linux等操作系统下配置方法如下:
<Host name="localhost" ...>
...
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html"
userClass="org.apache.catalina.startup.PasswdUserDatabase"/>
...
</Host>
在Windows等操作系统下配置方法如下:
<Host name="localhost" ...>
...
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html"
homeBase="c:\Homes"
userClass="org.apache.catalina.startup.HomesUserDatabase"/>
...
</Host>
这两种配置最主要的区别就是发现用户和为用户匹配路径。PasswdUserDatabase依据/etc/passwd发现用户而HomesUserDatabase依据homeBase="c:\Homes"发现用户。
User Web Applications是通过Listener(org.apache.catalina.startup.UserConfig)的方式实现的。即在Host启动时该Listener会被执行,它会为每一个发现的用户构建对应Context。
使用User Web Applications时需要考虑以下的一些问题:
- 依据DefaultContext来设置为每一个用户建立Context
- 可以使用多个Listener元素(在这么做之前您最好查阅一下UserConfig)
- 用户所对应的目录应该具有读写权限
从前面给出的 体系结构图 中可以看出,Automatic Context Configuration特性只在Context中都有支持。
如果使用标准的Context实现,当Catalina启动或Web应用装载时,会按如下的步骤自动进行设置:
- 如果没有指定Loader元素,那么一个标准的Loader将会被设置
- 如果没有指定Manager元素,那么一个标准的Manager将会被设置
- 如果没有指定Resources元素,那么一个标准的Resources将会被设置
- 处理conf/web.xml文件
- 处理/WEB-INF/web.xml文件
- 如果设置了security constraints,那么一个对应的Authenticator会被创建
从前面给出的 体系结构图 中可以看出,Context Parameters特性只在Context中有支持。
如下的两种配置等价,都是为Web配置初始参数:
<Context ...>
...
<Parameter name="companyName" value="My Company, Incorporated" override="false"/>
...
</Context>
<context-param>
<param-name>companyName</param-name>
<param-value>My Company, Incorporated</param-value>
</context-param>
从前面给出的 体系结构图 中可以看出,Environment Entries特性在GlobalNamingResources和Context中都有支持。
如下的两种配置等价,都是为配置environment entry resources:
<GlobalNamingResources ...>
...
<Environment name="maxExemptions" value="10" type="java.lang.Integer" override="false"/>
...
</GlobalNamingResources>
<env-entry>
<env-entry-name>maxExemptions</param-name>
<env-entry-value>10</env-entry-value>
<env-entry-type>java.lang.Integer</env-entry-type>
</env-entry>
这里使用GlobalNamingResources表示environment entry resources对于所有Web应用程序可见。如果换成Context则表示只对相应Web应用程序可见。
从前面给出的 体系结构图 中可以看出,Resource Definitions特性在GlobalNamingResources和Context中都有支持。
如下的两种配置等价,都是为定义Resource:
<GlobalNamingResources ...>
...
<Resource name="jdbc/EmployeeDB" auth="Container" type="javax.sql.DataSource"
description="Employees Database for HR Applications"/>
...
</GlobalNamingResources>
<resource-ref>
<description>Employees Database for HR Applications</description>
<res-ref-name>jdbc/EmployeeDB</res-ref-name>
<res-ref-type>javax.sql.DataSource</res-ref-type>
<res-auth>Container</res-auth>
</resource-ref>
这里使用GlobalNamingResources表示Resource对于所有Web应用程序可见。如果换成Context则表示只对相应Web应用程序可见。
从前面给出的 体系结构图 中可以看出,Resource Links特性在GlobalNamingResources和Context中都有支持。
ResourceLink
元素用来将资源从全局上下文(global context)中连接到每个Web应用的上下文(per-web-application
contexts)中。使用方式依据GlobalNamingResources和Context的不同分成两种:
<DefaultContext>
<ResourceLink name="bean/MyBeanFactory" global="bean/MyBeanFactory" type="com.mycompany.MyBean"/>
</DefaultContext>
<Context ...>
...
<ResourceLink name="linkToGlobalResource" global="simpleValue" type="java.lang.Integer"/>
...
</Context>
从前面给出的 体系结构图 中可以看出,Transaction特性在GlobalNamingResources和Context中都有支持。
通过在JNDI中查询java:comp/UserTransaction
可以得到UserTransaction的引用。
新浪微博:http://t.sina.com.cn/androidguy 昵称:李宁_Lining