从大学开始接触java web的开发时就开始使用tomcat部署web项目,对它的理解仅仅停留在"这是个开源免费的servlet容器"的阶段,后来也接触了一些tomcat的体系,原理等方面的知识,也是半知半解,最近又开始看这方面的东西,截止到写这篇博文,我也不没有完全理解它,但一些比较基础的东西总算有些眉目了,读源码不易,且行且珍惜,这里写篇笔记整理下.
Tomcat体系结构
先盗张图:
可以看到,Tomcat有一个最顶层的容器,也就是server容器,它最大,在server容器中,可以有多个service,由service来提供服务,所以service不能没有,至少得有一个.
在service中,主要包含两个组件,Connector和Container.Container上图中没有标出,其实就是包含了Engine的部分.
Tomcat可以提供多种协议的请求,http协议就是其中一种,这里以http请求为例,一个http请求发到服务器时,由Connector来接收并进行转换,Connector就是用来处理连接相关工作的组件,比如可以进行Socket与request,response之间的转换,container是一个包含了servlet等众多资源的库,它接受Connector传过来的request请求,解析出请求的资源,返回给Container,所以Connector和Container一个主外一个主内,两人共同建立起美满的家庭.
当然上述比喻是不严谨的,因为一个Service中只有一个Container,但却可以有多个Connector,下面一段代码来自Tomcat目录下conf下的server.xml:
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
</Service>
可以看到,默认的Tomcat服务配置文件有两个Connector,一个负责监听8080端口,一个负责监听8009端口,前者我们很熟悉了,它用来监听来自于浏览器的http请求,然后会new出一个线程来把请求传给Engine,而后者则是用来监听其他类型的servlet/jsp请求,叫AJP协议(我也没听说过).
Container体系结构
继续盗图,Container的体系结构:
Container是tomcat中容器的接口,我们最熟悉的Servlet就封装在Container的子接口Wrapper中.看一下Server.xml中的配置:
<Service name="Catalina">
<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" />
</Host>
</Engine>
</Service>
Container有四个子容器,根据图示以及xml配置就可以看出来他们是逐层包含的关系.
每个service中只有一个Engine,Engine中可以由多个Host,每个Host可以有多个Context,每个Context中可以有多个Wrapper,而每一个Wrapper里面就封装着一个Servlet.
下面分别简单总结几个容器:
Engine:顾名思义,引擎,它用来管理多个站点,也就是Host.
Host:表示一个站点,也可以叫做虚拟主机,在上面xml配置中,可以看到Tomcat默认配置了一个名为localhost的虚拟主机,我们部署,运行项目时,就默认进入这个站点,Tomcat回去webapps目录下去定位请求的web项目资源.
Context:意思是上下文,它表示一个应用程序,也就是我们开发的一个web项目,一个web项目就可以理解为一个Context.
Wrapper:每个Wrapper封装一个servlet.
默认配置下的webapps下的每一目录都是一个应用,其中有一个ROOT目录代表主应用,整个webapps表示一个站点(Host),当我们检测tomcat是否启动成功时一般都会打开http://localhost:8080/,这时候如果出现tomcat的官方站点就表示启动成功,其实这时候访问的就是ROOT应用下的资源,主应用就是直接使用域名访问就可以,假设webapps下还有一个helloword目录,如果你想访问helloword目录下的资源,就需要输入http://localhost:8080/helloword/.
conf目录下的配置文件server.xml
<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" />
</Host>
</Engine>
</Service>
</Server>
在server.xml 中首先配置了一个server,在8005端口监听关闭命令"shutdown".
Server里定义了一个名为Catania的Service,Service里定义了两个Connector,一个是HTTP协议,一个是AJP协议,此外还定义了一个名为Catalina的Engine,Engine里定义了一个名为localhost的Host.
Host中name属性表示域名,所以这个默认Host可以用localhost来访问,appBase属性指定了站点的位置,这里就是webapps目录,这里还有很多属性,详细介绍,可以参考这篇博文:http://www.blogjava.net/baoyaer/articles/107278.html
Container体系结构
没盗到图,自己画一张:
Connector是用来接收请求并把请求封装成Request和Response来进行具体的业务处理的,底层使用的Socket连接.
Connector实现了TCP/IP协议和HTTP协议,他会把Request和Response按照HTTP协议来进行封装,封装完之后交给Container来进行处理,待Container处理完之后,再返回回来,Connector使用Socket将返回结果返回给浏览器,完成整个处理请求.
下面简单介绍Connector中的几个重要组件
ProtocolHandler:处理不同连接类型的请求,比如普通Socket请求和NioSocket请求.
Endpoint:处理底层Socket的网络连接.实现的是TCP/IP协议.
Processor:将Endpoint接收到的Socket请求封装成Request,实现的HTTP协议.
Adapter: 将Request请求适配给Container来处理.
整个Tomcat服务器其实就是java编写的一个应用,我尝试着读了一些源码,但资历尚浅,读的很艰难,一些代码上的实现方式和原理也不懂,只能大概理解一些类的功能,所以这里只是简单总结一些比较肤浅的知识,以后,有决心和毅力再去研读.共勉.