Tomcat 组成与工作原理
共 3313字,需浏览 7分钟
· 2021-11-15
阅读本文大概需要 12 分钟。
来自:juejin.cn/post/6844903473482317837
Tomcat是什么
开源的 Java Web 应用服务器,实现了 Java EE(Java Platform Enterprise Edition)的部 分技术规范,比如 Java Servlet、Java Server Page、JSTL、Java WebSocket。Java EE 是 Sun 公 司为企业级应用推出的标准平台,定义了一系列用于企业级开发的技术规范,除了上述的之外,还有 EJB、Java Mail、JPA、JTA、JMS 等,而这些都依赖具体容器的实现。
上图对比了 Java EE 容器的实现情况,Tomcat 和 Jetty 都只提供了 Java Web 容器必需的 Servlet 和 JSP 规范,开发者要想实现其他的功能,需要自己依赖其他开源实现。
Glassfish 是由 sun 公司推出,Java EE 最新规范出来之后,首先会在 Glassfish 上进行实 现,所以是研究 Java EE 最新技术的首选。
最常见的情况是使用 Tomcat 作为 Java Web 服务器,使用 Spring 提供的开箱即用的强大 的功能,并依赖其他开源库来完成负责的业务功能实现。
Servlet容器
List
> results = new ArrayList >();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
boolean fail = false;
for (Futureresult :results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
复制代码
Server.xml 配置 Host 元素,指定 appBase 属性,默认$catalina.base/webapps/ Server.xml 配置 Context 元素,指定 docBase,元素,指定 web 应用的路径 自定义配置:在$catalina.base/EngineName/HostName/XXX.xml 配置 Context 元素
扫描 appbase 路径下的所有文件夹和 war 包,解析各个应用的 META-INF/context.xml,并 创建 StandardContext,并将 Context 加入到 Host 的子容器中。 解析$catalina.base/EngineName/HostName/下的所有 Context 配置,找到相应 web 应 用的位置,解析各个应用的 META-INF/context.xml,并创建 StandardContext,并将 Context 加入到 Host 的子容器中。
HostConfig 并没有实际解析 Context.xml,而是在 ContextConfig 中进行的。 HostConfig 中会定期检查 watched 资源文件(context.xml 配置文件)
先解析全局的配置 config/context.xml 然后解析 Host 的默认配置 EngineName/HostName/context.xml.default 最后解析应用的 META-INF/context.xml
先解析全局的配置 config/web.xml 然后解析 Host 的默认配置 EngineName/HostName/web.xml.default 接着解析应用的 MEB-INF/web.xml 扫描应用 WEB-INF/lib/下的 jar 文件,解析其中的 META-INF/web-fragment.xml 最后合并 xml 封装成 WebXml,并设置 Context
扫描 web 应用和 jar 中的注解(Filter、Listener、Servlet)就是上述步骤中进行的。 容器的定期执行:backgroundProcess,由 ContainerBase 来实现的,并且只有在顶层容器 中才会开启线程。(backgroundProcessorDelay=10 标志位来控制)
请求到达 server 端,server 根据 url 映射到相应的 Servlet 判断 Servlet 实例是否存在,不存在则加载和实例化 Servlet 并调用 init 方法 Server 分别创建 Request 和 Response 对象,调用 Servlet 实例的 service 方法(service 方法 内部会根据 http 请求方法类型调用相应的 doXXX 方法) doXXX 方法内为业务逻辑实现,从 Request 对象获取请求参数,处理完毕之后将结果通过 response 对象返回给调用方 当 Server 不再需要 Servlet 时(一般当 Server 关闭时),Server 调用 Servlet 的 destroy() 方 法。
根据 server.xml 配置的指定的 connector 以及端口监听 http、或者 ajp 请求 请求到来时建立连接,解析请求参数,创建 Request 和 Response 对象,调用顶层容器 pipeline 的 invoke 方法 容器之间层层调用,最终调用业务 servlet 的 service 方法 Connector 将 response 流中的数据写到 socket 中
JSP引擎
编译阶段:servlet 容器编译 servlet 源文 件,生成 servlet 类 初始化阶段:加载与 JSP 对应的 servlet 类, 创建其实例,并调用它的初始化方法 执行阶段:调用与 JSP 对应的 servlet 实例的 服务方法 销毁阶段:调用与 JSP 对应的 servlet 实例的 销毁方法,然后销毁 servlet 实例
代码片段:在_jspService()方法内直接输出 JSP 声明: 在 servlet 类中进行输出 JSP 表达式:在_jspService()方法内直接输出 JSP 注释:直接忽略,不输出 JSP 指令:根据不同指令进行区分,include:对引入的文件进行解析;page 相关的属性会做为 JSP 的属性,影响的是解析和请求处理时的行为 JSP 行为:不同的行为有不同的处理方式,jsp:useBean 为例,会从 pageContext 根据 scope 的 类别获取 bean 对象,如果没有会创建 bean,同时存到相应 scope 的 pageContext 中 HTML:在_jspService()方法内直接输出 JSP 隐式对象:在_jspService()方法会进行声明,只能在方法中使用;
Connector
JIO:用java.io编写的TCP模块,阻塞IO NIO:用java.nio编写的TCP模块,非阻塞IO,(IO多路复用) APR:全称Apache Portable Runtime,使用JNI的方式来进行读取文件以及进行网络传输
Support Polling:是否支持基于IO多路复用的socket事件轮询 Polling Size:轮询的最大连接数 Wait for next Request:在等待下一个请求时,处理线程是否释放,BIO是没有释放的,所以在keep-alive=true的情况下处理的并发连接数有限 Read Request Headers:由于request header数据较少,可以由容器提前解析完毕,不需要阻塞 Read Request Body:读取request body的数据是应用业务逻辑的事情,同时Servlet的限制,是需要阻塞读取的 Write Response:跟读取request body的逻辑类似,同样需要阻塞写
Comet
Begin:新的请求连接接入调用,可进行与Request和Response相关的对象初始化操作,并保存response对象,用于后续写入数据 Read:请求连接有数据可读时调用 End:当数据可用时,如果读取到文件结束或者response被关闭时则被调用 Error:在连接上发生异常时调用,数据读取异常、连接断开、处理异常、socket超时
Read:在post请求有数据,但在begin事件中没有处理,则会调用read,如果read没有读取数据,在会触发Error回调,关闭socket End:当socket超时,并且response被关闭时也会调用;server被关闭时调用 Error:除了socket超时不会关闭socket,其他都会关闭socket End和Error时间触发时应关闭当前comet会话,即调用CometEvent的close方法 Note:在事件触发时要做好线程安全的操作
异步Servlet
首先,Servlet 接收到请求之后,request数据解析; 接着,调用业务接口的某些方法,以完成业务处理; 最后,根据处理的结果提交响应,Servlet 线程结束
客户端发送一个请求 Servlet容器分配一个线程来处理容器中的一个servlet servlet调用request.startAsync(),保存AsyncContext, 然后返回 任何方式存在的容器线程都将退出,但是response仍然保持开放 业务线程使用保存的AsyncContext来完成响应(线程池) 客户端收到响应
onStartAsync:Request调用startAsync方法时触发 onComplete:syncContext调用complete方法时触发 onError:处理请求的过程出现异常时触发 onTimeout:socket超时触发
最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。