上QQ阅读APP看书,第一时间看更新
3.10 Tomcat服务器概述
Apache Tomcat是Java Servlet、JavaServer Pages、Java Expression Language和Java WebSocket技术的开源实现。Tomcat是在开放性和参与性环境中开发的,并在Apache License版本2下发布。
Apache Tomcat软件为各种行业和组织中的众多大型、关键任务Web应用程序提供支持。
3.10.1 Tomcat目录结构
Tomcat目录结构如下:
- bin:该目录下存放的是二进制可执行文件,如果是安装版,那么这个目录下会有两个.exe文件:tomcat9.exe和tomcat9w.exe,前者是在控制台下启动Tomcat,后者是弹出UGI窗口启动Tomcat;如果是解压版,那么会有startup.bat和shutdown.bat文件,startup.bat用来启动Tomcat,但需要先配置JAVA_HOME环境变量才能启动,shutdown.bat用来停止Tomcat。
- conf:这是一个非常重要的目录,这个目录有4个重要的文件:
server.xml:配置整个服务器信息,例如修改端口号、添加虚拟主机等。下面将会详细介绍。
tomcatuser.xml:存储Tomcat用户的文件,这里保存的是Tomcat的用户名、密码以及用户的角色信息。可以按该文件中的注释添加Tomcat用户,然后就可以在Tomcat主页中进入Tomcat Manager页面。
web.xml:部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。这些MIME类型是客户端与服务器之间的说明文档类型,如用户请求一个HTML网页,那么服务器会告诉客户端浏览器响应的文档是Text/HTML类型的,这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了,当然是在浏览器中显示这个HTML文件。但如果服务器响应的是一个.exe文件,浏览器就不可能显示它,转而会弹出下载窗口。MIME就是用来说明文档的内容是什么类型的。
context.xml:对所有应用的统一配置,通常我们不会去配置它。
- lib:Tomcat的类库,里面是一大堆JAR文件。如果需要添加Tomcat依赖的JAR文件,那么可以把它放到这个目录中,当然也可以把应用依赖的JAR文件放到这个目录中,这个目录中的JAR所有项目都可以共享,但这样你的应用放到其他Tomcat下时就不能共享这个目录下的JAR包,所以建议只把Tomcat需要的JAR包放到这个目录下。
- logs:这个目录中都是日志文件,记录了Tomcat的启动和关闭信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件中。
- temp:存放Tomcat的临时文件,这个目录下的东西可以在停止Tomcat后删除。
- webapps:存放Web项目的目录,其中每个文件夹都是一个项目。如果这个目录下已经存在目录,那么都是Tomcat自带的项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。访问http://localhost:8080/hello-servlet,进入示例项目。其中hello-servlet就是项目名,即文件夹的名字。
- work:运行时生成的文件,最终运行的文件都在这里是通过webapps中的项目生成的,可以把这个目录下的内容删除,再次运行时会再次生成work目录。当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,再编译生成Class文件。生成的Java和Class文件都会存放到这个目录下。
- LICENSE:许可证。
- NOTICE:说明文件。
3.10.2 Tomcat主要组件
Tomcat主要组件包括Server、Service、Connector、Container等。Tomcat结构示意图如图3-4所示。
图3-4 Tomcat结构示意图
- Connector:一个Connecter将在某个指定的端口上侦听客户请求,接收浏览器发过来的TCP连接请求,创建一个Request和Response对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的Request和Response对象传给处理Engine,从Engine处获得响应并返回客户。
- Container:Container是容器的父接口,该容器的设计用的是典型的责任链的设计模式,它由4个子容器组件构成,分别是Engine、Host、Context、Wrapper。
3.10.3 Tomcat处理HTTP请求的过程
Tomcat处理HTTP请求的过程如下:
- 该请求由正在ThreadPoolExecutor类中等待的单独线程接收。它正在等待常规ServerSocket.accept()方法中的请求。收到请求后,该线程将被唤醒。
- ThreadPoolExecutor分配一个TaskThread来处理请求。它还向catalina容器提供了JMX对象名称。
- 在这种情况下,处理请求的处理器是Coyote Http11Processor,并且调用了处理方法。同一处理器还将继续检查套接字的输入流,直到达到保持活动点或断开连接为止。
- 使用内部缓冲区类(Http11InputBuffer)解析HTTP请求。缓冲区类解析请求行、标头等,并将结果存储在Coyote请求(不是HTTP请求)中。此请求包含所有HTTP信息,例如服务器名、端口、方案等。
- 处理器包含对适配器的引用。解析请求后,Http11Processor会在适配器上调用service()。在服务方法中,请求包含CoyoteRequest和CoyoteResponse。CoyoteRequest实现了HttpRequest和HttpServletRequest。适配器通过Mapper解析所有内容并将其与请求、Cookie、上下文相关联。
- 解析完成后,CoyoteAdapter调用其容器(StandardEngine)并调用invoke(request,response)方法。这将从引擎级别开始向Catalina容器发起HTTP请求。
- StandardEngine.invoke()只需调用容器管道.invoke()。
- 默认情况下,引擎只有一个阀门StandardEngineValve,该阀门仅在主机管道上调用invoke()方法。
- 默认情况下,StandardHost具有两个阀门,即StandardHostValve和ErrorReportValve。
- 标准主阀将正确的类加载器与当前线程相关联。它还会检索Manager和与请求关联的会话(如果有)。如果存在会话,就调用access()来保持会话有效。
- 之后,StandardHostValve在与请求关联的上下文上调用管道。
- 上下文管道调用的第一个阀是FormAuthenticator阀,然后StandardContextValve被调用。StandardContextValve调用与上下文关联的所有上下文侦听器。接下来,它调用Wrapper组件(StandardWrapperValve)上的管道。
- 在调用StandardWrapperValve期间,将调用JSP包装器,这导致了JSP的实际编译,然后调用实际的Servlet。