tomcat中的组件机制是tomcat的技术建构中非常重要的一个机制。也是软件设计中一个很重要的思路。如下面的Server.xml 就是描述tomcat中各个组件配置的元信息。
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<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 "%r" %s %b" resolveHosts="false"/>
</Host>
</Engine>
</Service>
</Server>
下面就从每个组件入手来详细分析每个组件的类图和作用,以及每个组件中属性的作用来介绍一下。
1. Server组件是tomcat最顶层的组件,Server组件可以包含一个Service组件,但是不能包含Valve等其他组件。Server组件的两个属性:port:指定一个端口,这个端口负责监听关闭tomcat的请求,shutdown:指定向端口发送的命令字符串。
.service:属性name:指定service的名字,Service组件是作为Engine和connector的父容器而存在的,Service中定义的多个connector都有Engine处理。
Connector(表示客户端和service之间的连接):port 指定服务器端要创建的端口号,并在这个断口监听来自客户端的请求 。minProcessors服务器启动时创建的处理请求的线程数 maxProcessors最大可以创建的处理请求的线程数 enableLookups
如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址 redirectPort指定服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号 acceptCount指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理 connectionTimeout指定超时的时间数(以毫秒为单位)
Engine(表示指定service中的请求处理机,接收和处理来自Connector的请求):属性:defaultHost 指定缺省的处理请求的主机名,它至少与其中的一个host元素的name属性值是一样的
Context(表示一个web应用程序,通常为WAR文件,关于WAR的具体信息见servlet规范)docBase
应用程序的路径或者是WAR文件存放的路径 path表示此web应用程序的url的前缀,这样请求的url为http://localhost:8080/path/**** reloadable 这个属性非常重要,如果为true,则tomcat会自动检测应用程序的/WEB-INF/lib 和/WEB-INF/classes目录的变化,自动装载新的应用程序,我们可以在不重起tomcat的情况下改变应用程序
Valve 做过滤用,责任链模式的体现
总结:对于常用的接口提供一个实现该接口的抽象类,是一种好的设计模式。Valve 通过实现Contained来表明Valve必须被包含在某个容器中,非常好的设计。每个接口代表一个功能,实现该接口就有该功能,如通过是否实现Container接口来判断是否可以放其他组件。各个组件之间可以单独开发,单独测试,因为每个组件对于别的组件的引用都是接口层的,故相互之间的耦合度会非常的低。通过实现container接口来表明可以作为容器,通过实现Contained接口来表示必须被包含。而不是通过在父容器上加isXX或者hasXXX方法等,这种通过接口的方式实现,更整洁,更优雅。