Tomcat处理请求的过程
Tomcat通过EndPoint组件来接收socket请求,在接收到一个socket请求后会执行以下步骤
1.第一次冲socket获取数据到InputBuffer中,BIO是InternalInputBuffer,父类是AbstractInputBuffer.
2.基于InputBuffer解析数据
3.解析请求行,将请求方法,请求uri,请求协议等封装到org.apache.coyote.Request对象中。
4.解析请求头,和请求行类型
5.基于请求头初始化一些参数,例如content-length等
6.然后将请求交给容器,容器将请求交给对应的servlet处理
7.servlet处理过程中会用response进行响应,将数据写给客户端,普通的响应会向把数据写到缓冲区,当调用flush或close时将数据写到socket
8.当selvlet处理完后,会先检查是否需要将响应发送给socket,如果还有数据未处理,需要将剩余数据处理,以便能够获取到下一个请求的数据。
9.回到第一步开始处理下一个请求。
Tomcat响应请求的过程
1.CoyoteOutputStream.write()
2.OutputBuffer.writeBytes
3.ByteChunk.realWriteBytes,此时会把数据发给对应驱动
BIO
JioEndPoint里的Acceptor负责循环阻塞接收socket连接,每接收到一个socket连接就包装成SocketProcess丢到线程池里,SocketPreccess负责从socket里阻塞读取数据,并往socket里阻塞写入数据,Acceptor默认就一个线程,可以通过配置acceptorThreadCount参数调整线程数量。
当请求量大时可以适当增加Acceptor线程数量,当请求比较耗时可以适当增加线程池的最大线程数,当然线程数量并非越多越好,还需要通过压测来确定合适的线程数量。
NIO
nio的最大特点就是非阻塞,非阻塞接收请求,非阻塞接收socket数据,非阻塞向socket写入数据。
但在Tomcat7中只是读取请求头时非阻塞,读取请求行时还是阻塞的,这是因为tomcat对应的是Servlet3.0规范,规范中并没有考虑nio,读取数据时使用inputStream.read(),当操作系统没有准备好请求行数据时,read()是阻塞的。
Tomcat的自定义类加载器
tomcat有不同的自定义类加载器来实现对不同资源库的加载,tomcat主要用自定义类加载器解决了以下问题:
1.同一个Tomcat下的不同应用之间的类库要相互隔离
2.同一Tomcat下的不同应用可以提供共享的类库
3.为了使tomcat不受web引用的影响,应该使应用服务器的类库和程序类库隔离
4.支持热部署
tomcat下的几种自定义类加载器:
CommonClassLoader:父加载器是应用类加载器,负责加载$CATALINA_ BASE/lib、$CATALINA_HOME/lib 两个⽬录下所有的.class ⽂件与.jar ⽂件
WebAppClassLoader:Tomcat一般会有多个WebAppClassLoader,父类加载器是CommonClassLoader,每个Web加载器负责加载一个Web应用
Tomcat架构
Tomcat启动过程
1.解析server.xml
2.解析出来的对象进行初始化,server.init()
3.容器启动,部署server.xml下定义的Context,部署webapp目录下的Context
4.应用启动,生产WebappClassLoader,将WEB-INF/classes,WEB-INF/lib目录作为web应用加载器的加载路径,解析web.xml,创建WebXml对象
5.Connector启动,启动EndPoint开始接收请求,构建Mapper对象,用来处理请求时能够快速解析出请求对应的哪个Context,哪个Wrapper
热加载
可以在Context上配置reloadable属性为true,表示开启热部署,默认是false,热部署的触发条件是WEB-INF/classes里的文件发生变化,或者WEB-INF/lib下的jar发生删除,添加,修改。
热加载的大致过程:
1.设置当前Context不能接受和处理请求标志为true
2.停止当前Context
3.启动当前Context
4.设置当前Context不能接受和处理请求标志为false
热部署
应⽤部署的优先级,对于⼀个应⽤,我们可以在四个地⽅进⾏定 义:
1. server.xml中的context节点
2. /tomcat-7/conf/Catalina/localhost/应⽤名.xml
3. /tomcat-7/webapps/应⽤名.war
4. /tomcat-7/webapps/应⽤名
优先级就是上⾯所列的顺序,意思是同⼀个应⽤名,如果你在这个四个地⽅都配置了,那么优先级低的将不起作⽤。因为Tomcat在部署⼀个应⽤的时候,会先查⼀下这个应⽤名是否已经被部署过了。
对于⼀个⽂件夹部署的应⽤,通常会检查以下资源是否发⽣变动:
/tomcat-7/webapps/应⽤名.war
/tomcat-7/webapps/应⽤名
/tomcat-7/webapps/应⽤名/META-INF/context.xml
/tomcat-7/conf/Catalina/localhost/应⽤名.xml
/tomcat-7/conf/context.xml
对于⼀个War部署的应⽤,会检查以下资源是否发⽣变动:
/tomcat-7/webapps/应⽤名.war
/tomcat-7/conf/Catalina/localhost/应⽤名.xml
/tomcat-7/conf/context.xml
对于⼀个描述符部署的应⽤,会检查以下资源是否发⽣变动:
/tomcat-7/conf/Catalina/localhost/应⽤名.xml
指定的DocBase⽬录
/tomcat-7/conf/context.xml
热部署的开关在host上,默认是开启的。
因为热加载监听的是WEB-INF/classes和WEB-INF/lib⽬录,而热部署监听的是应用名那⼀层的目录,所以热加载和热部署不会相互冲突。