Tomcat是一个开源的轻量级web应用服务器。整体架构如下:
Connector中使用ProtocolHandler来封装不同的IO模式和应用协议组合,例如NIO模式和HTTP1.1协议对应的就是Http11NioProtocol类。在配置文件中配置Connector的protocol属性值为Http11NioProtocol即使其成为支持NIO和HTTP1.1的连接器。
<Connector port="8080" executor="tomcatThreadPool" protocol="org.apache.coyote.http11.Http11NioProtocol"
redirectPort="8443" enableLookups="false" URIEncoding="UTF-8" maxKeepAliveRequests="500" />
Tomcat8前默认为BIO模式,Tomcat8.0起默认为NIO模式,并在Tomcat8.5起移除了BIO模式
在ProtocolHandler中,EndPoint类负责Socket请求的收发,Processor类负责从Socket中解析出对应协议格式的数据并封装为Request 或者反向。然后通过适配器Adapter将Request转换为标准的ServletRequest传递给Servlet容器进行处理。这样每个模块只负责必要的部分,实现功能模块的高内聚和低耦合,
在BIO实现的Connector中,处理请求的主要实体是JIoEndpoint对象。JIoEndpoint维护了Acceptor和一个线程池:Acceptor负责接收socket,然后从线程池中找出空闲的线程处理socket,如果线程池没有空闲线程,则Acceptor将阻塞。
在NIO实现的Connector中,处理请求的主要实体是NIoEndpoint对象。在NIoEndpoint中Acceptor接收socket后,不是直接放到线程池中处理,而是先将socket封装为一个Channel放进Poller的通道队列中,而Poller是实现NIO的关键,在Poller中,维护了一个Selector选择器对象,Poller从通道队列中取出socket后注册到该Selector中,然后通过Selector轮询,找出其中可读的socket,并放到线程池中进行后续处理。
Acceptor和Poller默认都是单线程的,而线程池默认使用的Tomcat自己定制的线程池,在JDK的线程池ThreadPoolExecutor中只有当任务等待队列满了才会启动非核心线程,但是在TomcatThreadPool中当核心线程数满了之后就会启动非核心线程,以便请求能够快速得到响应。
容器中有如下四个组件,并且这四个组件是具有层次关系的:一个Engine下可以有多个Host,一个Host下可以有多个Context,一个Context下可以有多个Wrapper,一个Wrapper下可以有多个Servlet实例对象。
Engine:一个容器Container中有一个Engine
Host:一个Host表示一个虚拟服务器,可以给每个Host配置一个域名
Context:一个Context就是一个应用,一个项目
Wrapper:一个Wrapper是对Servlet的包装,一个Wrapper下可以有多个Servlet实例对象。
在连接器生成请求的Request对象后,传递到容器执行处理的过程如下:
server.xml是Tomcat的核心配置文件,定义整个Tomcat服务器的架构。其默认的主要配置如下:
<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">
<Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="true">
<Context >
<Context />
Host>
Engine>
Service>
Server>
其中定义
上述默认Host配置中appBase="webapps“表示默认应用,Tomcat目录下:d:\tomcat\webapps 这样的路径,实际可以指定多个自定义的Context应用:
<Host name="localhost" unpackWARs="true" autoDeploy="true">
<Context path="/js" docBase="E:\eclipse\java_web\jspPrime\webapps" reloadable="true"/>
<Context path="/word" docBase="D:\apache-tomcat-7.0.35\webapps"/>
Host>
在Context应用目录下,需要有一个web.xml文件,用于配置Filter、Servlet类等的路径及其匹配路径。一个样例如下
<web-app>
<display-name>MyWebappdisplay-name>
<filter>
<filter-name>globalfilter-name>
<filter-class>com.xxxx.MyFilterfilter-class>
<init-param>
<param-name>testparam-name>
<param-value>1param-value>
init-param>
filter>
<filter-mapping>
<filter-name>globalfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<servlet-name>MyHttpServletservlet-name>
<servlet-class>com.xxxx.MyHttpServletservlet-class>
<init-param>
<param-name>testPparam-name>
<param-value>falseparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>MyHttpServletservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
web-app>
参考: