Tomcat --执行流程

摘要:#1.Tomcat组成 tomcat的server.xml配置 <?xml version=\'1.0\' encoding=\'utf-8\'?>

#1.Tomcat组成
tomcat的server.xml配置

002UASMrzy7605pjKJv15&690.jpg

<?xml version=\'1.0\' encoding=\'utf-8\'?> <!-- tomcat(启动后)监听端口8005,如果收到SHUTDOWN命令,则关闭服务器--> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <!-- Prevent memory leaks due to use of particular java/javax APIs--> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <!-- Global JNDI resources Documentation at /docs/jndi-resources-howto.html --> <GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <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命名,service是一组Connector,它们共用一个Engine来处理所有的controller请求 --> <Service name="Catalina"> <!--端口号8080用于监听来自客户端的http请求 minProcessors:该Connector先创建minProcessors个线程等待客户请求,每个请求由一条线程负责。 maxProcessors:设置server处理的最大线程数,当现有的线程数(maxProcessors) 小于 客户端的请求时,则自动创建新的线程来处理,但是最多只能为maxProcessors。 acceptCount:设置客户请求排队数,当现有的线程数已经达到maxProcessors时,为客户请求排队,当排队数超过acceptCount时,再后来的请求返回Connection refused错误。 redirectport:将请求转到8443端口去处理 connectionTimeout:设置连接超时时间 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!-- Engine用来处理接收到的请求,将请求转发给对应的host来处理, 默认的虚拟主机是localhost --> <Engine name="Catalina" defaultHost="localhost"> <!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <!-- 设置虚拟主机相关属性,主机名localhost appBase:虚拟主机的根目录,这里设为webapps/,它匹配请求与Context, 将请求转发给对应的Context处理。所以,需要将app.war包放在tomcat的webapps 目录下。 --> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <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" /> <!-- Context是一个上下文容器,处理Host转过来的请求。即扫描webApp的web.xml文件。 docBase:web应用文件的物理路径,即绝对路径 path:虚拟目录,指请求访问该web应用的url入口 reloadable:true表示tomcat服务器在运行状态下会监视WEB-INF/classes和 WEB-INF/lib目录下class文件的改动,如果检测到有class文件被更新,则web服务器会自动重新加载web应用。 --> <!-- <Context docBase="D:/resource/testSQL" path="/testSQL" reloadable="true" source="org.eclipse.jst.j2ee.server:testSQL"/> --> </Host> </Engine> </Service> </Server>

由server.xml文件可知,tomcat的组成包括
1.server:它表示真个servlet容器
2.service:它由Connector(一个或多个)、Engine(负责处理所有Connector获得的请求)组成。
3.Connector:它监听客户端请求,将请求交给Engine处理;从Engine获取处理值再返回给客户。Tomcat通常有两个Connector,端口为8080(默认,可以修改)的一直监听来自http的请求;另一个端口(8009)监听AJP(协议)请求。
4.Engine:Engine下可以配置多个虚拟主机,当获取一个请求时,它将该请求分配到某个Host上,然后将该请求交给Host处理。
5.Host:表示一个虚拟主机,每个虚拟主机下可以部署一个或多个webApp,每个webApp对应一个Context,每个Context都有一个Context Path。当Host获得一个请求时,将该请求匹配到某个Context上,然后将该请求交给Context来处理。
6.Context:一个Context对应一个webApp,一个webApp由一个或多个Servlet组成,Context在创建的时候根据配置文件$<CATALINA_HOME>/conf/web.xml()与/webapps/WEB-INF/web.xml(app应用下面的web.xml)。这样就将tomcat与app关联起来了。
#2.web.xml简介
一个Context对应一个webApp,每个webApp由一个或多个Servlet组成,当一个webApp被初始化的时候,它用自己的ClassLoader对象载入"部署文件目录下的web.xml"中定义的每个Servlet类,它先载入tomcat的/conf/web.xml中部署的servlet,然后载入webApp根目录下WEB-INF/web.xml中部署的类。
web.xml文件有两个部分:Servlet类定义和Servlet映射定义,每个被载入的Servlet类都有一个名字,并且都会被填入该Context的映射表中,与url-pattern值对应,当Context获得请求的时候,将查询mapping list,找到被请求的servlet,并执行请求。
web.xml如下

<?xml version="1.0" encoding="ISO-8859-1"?> <!-- 引言:该文件是所有的webApp通用的配置文件,每当一个webApp被加载时,该文件首先被加载,其次再加载webApp的/WEB-INF/web.xml。 --> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- default的servlet 当用户的请求无法匹配任何一个servlet的时候,该servlet被执行 --> <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- 当请求的是一个jsp页面的时候,该servlet被调用 它是一个jsp编译器,将请求的jsp页面编译成servlet再执行 --> <servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredBy</param-name> <param-value>false</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- The mappings for the JSP servlet --> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> </servlet-mapping> <!-- 其它的省略 --> </web-app>

#3.tomcat server处理一个http请求流程
假设客户端的请求为:http://localhost:8080/testSQL/index.jsp
1.请求被发到localhost的8080端口,被tomcat监听器获取

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

2.Connector获得请求http://localhost:8080/testSQL/index.jsp,将请求转给它所在的service的Engine处理

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

3.Engine获得请求localhost/testSQL/index.jsp,将请求转给它匹配的Host处理

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

很明显,可以匹配到主机名为localhost的主机.(注意:localhost是Engine的默认主机,如果Connector没有匹配到主机,由于设置了defaultHost="localhost",也会转给localhost处理)。
4.Host获得请求/testSQL/index.jsp,匹配它所拥有的所有的Context,匹配路径是/testSQL的Context,如果没有匹配到就返回错误信息(路径找不到,这里可以配置一个默认的路径,用于处理找不到路径时返回404.jsp)。

<Context docBase="D:/resource/testSQL" path="/testSQL" reloadable="true" />

5.path="/testSQL"的Context获得了/testSQL/index.jsp请求,Context是一个上下文,它加载tomcat的web.xml和app的web.xml,去app的web.xml中匹配servlet-name=testSQL的servlet,然后匹配该servlet-mapping对应的url-pattern值(一般会在这里做一些限制)

<!-- 工程映射 --> <servlet> <servlet-name>testSQL</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>testSQL</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>

如上,我这里配置成/*,即没有做任何拦截操作,所有的请求均可以通过。
6.匹配servlet成功,调用servlet的doGet或doPost方法
匹配成功,即构造HttpServletRequest对象和HttpServletResponse对象 作为参数 调用servlet的doGet或doPost方法。
6-1 转折
由如上的配置信息可知,加载servlet-name=testSQL的时候,会调用DispatcherServlet这个类,并且初始化 spring-config.xml配置文件,DispatcherServlet这个类会分发路径到每个contrller,匹配到这个路径的controller执行处理。

@RestController public class UserController { @Autowired private UserService userService; /** * 获取用户列表 */ @RequestMapping(value="/index.jsp",method= RequestMethod.GET) public void getUserList() { userService.getUserList(); } }

7.处理返回结果
如上处理是在tomcat的Context中,controller执行完后,将结果由HttpServletResponse对象返回给host;host将HttpServletResponse对象返回给Engine;Engine再返回给Connector,Connector在将HttpServletResponse对象返回给客户端browser。