Tomcat深度复盘

发布于 2020-12-16  3.79k 次阅读


一,Tomcat

一,WEB服务器

WEB服务器:安装了web服务器软件的计算机,它是一个通过HTTP协议处理WEB请求的计算机系统

WEB服务器软件功能:接收用户请求,处理请求,做出响应

一,常见的WEB服务器软件

一,收费的非开源服务器软件

①weblogic:oracle公司开发的,大型javaEE服务器,支持所有的java规范

②jboss:jboss公司开发,大型javaEE服务器,支持所有的java规范

③webSphere:IBM公司开发,大型javaEE服务器,支持所有的java规范

……

二,开源的服务器软件

①Tomcat:Apache基金会开源的服务器,中小型web服务器,仅仅支持少量的javaEE规范如servlet/jsp

②Nginx:Igor Sysoev开发,一款轻量的WEB反向代理服务器(反向代理:代理服务器),主要用于服务器的负载均衡

③Node.js:由Ryan Dahl开发,实际上是对Chrome V8引擎的封装,Node.js对一些特殊用例进行优化,提供替代的API,基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用,天生适应于在大型数据集的分布式实时应用

……

开源与收费的web服务器实际上本质是一样的只是API和应用的性能有不同

二,Tomcat的目录结构

Tomcat 9.0的下载地址:https://downloads.apache.org/tomcat/tomcat-9/v9.0.41/bin/apache-tomcat-9.0.41-windows-x64.zip

一,Tomcat的目录结构

一级目录下的文件:

① bin:Tomcat的可执行文件

② conf:Tomcat的一系列配置文件

③ lib:Tomcat的依赖jar包(servlet-api.jar:servlet依赖jar包)

④ logs:Tomcat系统日志文件

⑤ tmep:存放Tomcat运行产生的临时文件

⑥ webapps:默认应用程序文件位置,WEB项目在此文件夹中,Tomcat启动时会默认加载这个目录下的应用程序,可以以jar包,war包,文件夹的方式,但需要配置web.xml做好映射

⑦ work:存放Tomcat运行时产生的编译产生的CLASS文件,例如:jsp编译的文件,但系统重启时会自动删除文件和缓存

二级目录下的文件:

一,bin目录

.sh后缀:是Linux系统的脚本

.bat后缀:以Windows系统的脚本

二,conf目录

conf目录有四个比较重要的子文件

server.xml:配置容器和连接器的信息,在连接器中可以配置端口

web.xml:在conf目录下的web.xml是默认的配置(在单独的web项目下也要配置web.xml但你的配置的父配置是这个文件),主要配置servlet映射信息,初始化信息,过滤器

tomcat-users.xml:配置tomcat用户信息

context.xml:配置上下文信息

三,lib目录

lib主要是Tomcat的依赖jar包

在里面有一个selvet的jar包依赖

其他不详说

四,logs日志目录

Tomcat的日志文件目录下,日志文件也分几类

localhost:本地tomcat运行日志

catalina:catalina容器的日志文件

host:虚拟主机的日志文件

五,webapps目录(可以在server配置文件中更改默认访问资源路径)

Webapp目录下的默认文件:

docs:Tomcat的系统项目文件

host-manager:虚拟主机项目,在manager.xml可以配置用户

manager:Tomcat项目的管理员项目,在manager可以配置整个Tomcat的管理员

ROOT:在默认访问Tomcat,没有加任何访问资源路径时,默认访问这个ROOT项目

Webapps中搭建项目(重点):

在Webapp是的直接路径下资源分两类:

1,WEB-INF资源

2,其他资源

3,web.xml配置文件

WEB-INF目录:
特点:不能被Tomcat直接访问的资源,必须要在web.xml配置servlet的映射才能访问

必须组成部分:

lib文件夹:项目依赖的jar包

classs文件夹:项目的java文件编译后的class文件存放位置

其他资源文件:可以在Tomcat下通过资源路径直接访问

案例:

项目资源路径:

通过Tomcat访问资源:

六,work目录

work会在catalina的localhost中会按照webapps的文件,把不同项目建一个文件,出发没一个项目的编译的class文件

三,Tomcat的源码编译部署

下载Tomcat源码包:https://downloads.apache.org/tomcat/tomcat-8/v8.5.61/src/apache-tomcat-8.5.61-src.zip

步骤:

①在IDEA中创建一个空项目

②在空项目目录下解压源码压缩包

这个时候空项目下并不会有任何文件,需要maven导入

③在解压源码目录下新建一个pom.xml文件

内容:

<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>Tomcat8.5</artifactId>
    <name>Tomcat8.5</name>
    <version>8.5</version>
    <build>
        <finalName>Tomcat8.0</finalName>
        <!-- 指定源文件为java 、test -->
        <sourceDirectory>java</sourceDirectory>
        <testSourceDirectory>test</testSourceDirectory>
        <resources>
            <resource>
                <directory>java</directory>
            </resource>
        </resources>
        <testResources>
            <testResource>
                <directory>test</directory>
            </testResource>
        </testResources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <!-- 指定jdk 编译 版本 ,没装jdk 1.7的可以变更为1.6 -->
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <!-- 添加tomcat8 所需jar包依赖 -->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.2</version>
        </dependency>
        <dependency>
            <groupId>javax.xml</groupId>
            <artifactId>jaxrpc</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>3.3</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt.core.compiler</groupId>
            <artifactId>ecj</artifactId>
            <version>4.6.1</version>
        </dependency>
    </dependencies>
</project>

④ 在IDEA中导入pom.xml

这样就有源码项目了

⑤运行源码的main方法位置

Java -> org.apache  -> catalina ->startup ->Bootstrap ->main

四,Tomcat的架构

一,HTTP请求的过程

HTTP请求过程:

  1.  用户在浏览器输入HTTP请求
  2. 浏览器解析域名,获取IP地址,向服务器发送请求
  3.  Tomcat服务器接收请求,让HTTP服务器,解析HTTP请求,并将请求转换成一个对象,交给servlet容器
  4. servlet接受HTTP服务器发来的请求,调用具体的业务类处理,并响应数据
  5. HTTP服务器转换对象为一个请求,响应给浏览器
  6. 浏览器解析数据并展示

上面的HTTP服务器只是一个概念性的东西,Tomcat并没有具体的这个东西,Tomcat的连接器(cannector)通常是这个职责

Servlet其实是一个解耦容器,它避免了HTTP服务器之间掉用业务类,

反观Tomcat服务器软件也是一个容器,它避免了浏览器直接请求服务器上面的资源

二,Tomcat的组成模块

Tomcat的组成模块,是相互进行的

  • Catalina:Tomcat的核心Servlet容器,一个Catalina有一个Server,当一个Server有多个Service,每个Service都有Catinaer子容器
  • Coyote:连接器,它其实也不是独立存在的,它一般在Catalina中体现
  • Jasper:Jsp的解析引擎
  • javaEL:Tomcat的特定表达式

不同模块在Tomcat源码中也有体现

三,Conector连接器

连接器的作用和功能:

  1. 对浏览器而言:处理浏览器的网络请求,处理Socket连接,解析请求协议,对容器返回的结果进行处理在返回给浏览器
  2. 对Catinaor容器而言,转换请求,把浏览器的HTTP请求转换成Request

Conector和coyote的关系:Conector是一个模块,Coyote是一个具体的连接器框架

一,coyote连接器框架

1,coyote是Tomcat供客户端访问的外部接口,客户端通过coyote与服务器建立连接,发送请求并接收响应

2,coyote封装了底层的网络通信(Socket的请求,响应,处理),为Catalina容器提供统一的接口,使容器与具体协议,IO完全解耦,Coyote建Socket连接请求转换成Requst对象,交给容器处理,容器的响应通过Coyote转换发送给客户端

3,Coyote是独立于catalina的存在,它只负责协议和IO的存操作处理,与Servlet的规范没有直接关系,因此Coyote的Request和Response也没有实现servlet规范,需要在Catalina进行进一步处理,产生ServletRequest和ServletResponse

Coyote与Catalina的交互过程:

Coyote支持的IO模型和应用层协议:

IO模型:

  1. NIO:非阻塞IO,Java Nio类库实现
  2. NIO2:异步IO,采用JDK7的NIO2类库实现
  3. APR:采用Apache可移植性运行类库实现,C/C++编写的本地库,如果选择该方案协议单独安装APR库

应用层协议:

  1. HTTP/1.1:这是大部分web应用采用的协议
  2. AJP:用于大型的WEB集成(Apache开源框架),实现静态资源的优化和集群的部署
  3. HTTP/2:大幅度提示了WEB系统的性能,在Tomcat8.5之后的版本支持

coyote的协议分层;

二,Coyote组件

Coyote的组件主要包括三个部分:

  1. EndPint:Coyote的通信端点,Socket接口监听,对传输层的抽象,负责处理Socket请求和响应,EendPint实现了TCP/IP协议
  2. Processor:Coyote的应用层协议的处理接口,Endpint处理传输层后交由Processor处理HTTP
  3. Adapter:遵循了Servlet规范,将Request请求转化成ServletRequest请求
  4. ProtocolHandler:Coyote的主容器,代表着对一种协议的支持,比如tomcat默认支持的协议有http1.1和ajp。根据支持的协议,ProtocolHandler里面通常包含了一个实现对应协议的Handler接口的处理类,用于接收socket对象,再交给对应协议的Processor类(然而这个Processor类没有实现Processor接口,而是实现了ActionHook接口),最后由Processor类交给实现了Adapter接口的容器(准确的说是该容器的Pipeline的第一个Valve)

四,Catalina容器

Catalina的功能:Catalina负责管理Server,而Server表示整个服务器,Server下面有多个Service服务,而每一个server都包含多个Connection(连接器Coyote框架实现)和Container容器在Tomcat启动时会初始化一个Catalina实例

Catalina各个组件的职责:

  1. Server:Server表示服务器,而服务器表示整个Catalina Servlet容器以及其他组件,负责组装并启动Servlet引擎,Tomcat连接器。server通过实现实现Lifecycle,提供了一系列启动关闭的系统的方式
  2. Service:服务器Server的内部组件,一个Server包含多个Servlet,它将若干个Conector绑定到Container(Engine)上
  3. Connector:连接器,处理客户端的通信
  4. Container:容器,负责处理用户Servlet请求

在API中Tomcat提供了一系列Catalina操作:

一,Container结构

Container设计了四种子容器,分别是Engine,host,context,webapps,这四种子容器不是平行关系而是父子关系

职责:

  1. Engine:表示整个Cataliner的Servlet引擎,用来管理多个虚拟站点,一个Service最多只能有一个Container,而一个Container也只能有一个Engine,当一个Engine有多个Host
  2. Host:代表一个虚拟主机(一个站点),可以给tomcat配置多个虚拟主机,而host可以包含多个Context
  3. Context:表示一个WEB应用程序,一个WEB应用有多个Webapps
  4. Webapps:表示一个Servlet,容器的最底层

它们的XML表示:

    </Host>

    </Engine>

  </Service>

</Server>

五,Jasper引擎

Jasper说白了就是一个Servlet,只是功能场景不一

Jasper是tomcat中使用的JSP引擎,在Tomcat 6中使用的是Jasper 2,相对于原来的版本作了不少的改进,比如:JSP的标签缓冲池、后台编译、页面改变时自动重新编译、Eclipse中JDT编译等等。

五,Tomcat服务器配置

一,Server和Service的配置

Server和Service的配置主要在Tomcat的conf目录下的server.xml中

 

1,Server标签(根标签)

Server是server.xml的根元素,用于创建一个Server实例,默认的使用类:org.apache.catalina.StandardServer

<Server port="8005" shutdown="SHUTDOWN">

</Server>

port:监听的关闭服务器端口

shutdown:关闭服务器的指令字符串

Server标签的内嵌元素:

  1. Listener:监听器
  2. Service:服务,包含Containe容器
  3. GlobalNamingResources:全局命名服务

默认的五个监听器含义:

 <!--用于日志形式输出,操作系统,JVM版本信息 -->
 <Listener className="org.apache.catalina.startup.VersionLoggerListener" />

  <!--用于加载服务器和销毁服务器和APR -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

  <!--避免JRE内存泄漏问题-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

  <!--全局命名服务-->
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  
  <!--线程相关-->
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

GlobalNamingResources全局命名服务:

  <GlobalNamingResources>

    <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实例,默认使用的类org.apache.catalina.core.StandardService,默认情况下只指定Service的名称name,值为"Catalina"

Serive的内嵌元素:

  1. Listener:为Service添加生命周期的监听器
  2. Executor:配置线程池信息
  3. Connector:用于配置Service连接器
  4. host:虚拟主机信息
  5. Engine
  <Service name="Catalina">

  </Service>

二,Executor线程池

下面显示了Executor的属性。

属性:className、含义:Executor实现的完全限定的Java类名、默认值:org.apache.catalina.core.StandardThread-Executor。

属性:daemon、含义:决定这一Executor的线程是否应该为后台线程。如果JVM中的所有其他非后台线程都结束了,则后台线程结束。

要获得有关后台线程的详细解释,参见java.lang.Thread的Java 1.5(及更高版本)Javadoc网页、默认值:false。

属性:name、含义:共享线程池的名字。这是Connector为了共享线程池要引用的名字。该名字必须唯一、默认值:None;需要的参数。

属性:namePrefix、含义:在JVM上,每个运行线程都可以有一个name 字符串。这一属性为线程池中每个线程的name字符串设置了一个前缀,Tomcat将把线程号追加到这一前缀的后面、默认值:tomcat-exec-。

属性:maxIdleTime、含义:在Tomcat关闭一个空闲线程之前,允许空闲线程持续的时间(以毫秒为单位)。只有当前活跃的线程数大于minSpareThread的值,才会关闭空闲线程、默认值:60000(一分钟)。

属性:maxThreads、含义:该线程池可以容纳的最大线程数、默认值:200。

属性:minSpareThreads、含义:Tomcat应该始终打开的最小不活跃线程数、默认值:25。

属性:threadPriority、含义:整数值,表示线程池中所有线程的线程优先权

三,Connector连接器的配置

    <Connector protocol="HTTP/1.1" port="8080" address="${jboss.bind.address}"
               connectionTimeout="20000" redirectPort="8443" compression="on"  
               compressionMinSize="1" compressableMimeType="text/html,text/xml" />

属性:

allowTrace 如果需要服务器能够处理用户的HAED/TRACE请求,这个值应该设置为true,默认值是false;

emptySessionPath 如果设置为true,所有session,cookie的path将会被设置为/,这种设置通常是在portlet中比较有用,默认值是false;

enableLookups 如果需要在调用request.getRemoteHost()方法时获取到客户端的机器名,则需要配置为true,如果配置为false,将会跳过DNS查询直接返回客户端机器的IP地址,通常为了提高性能,将此值设置为false,默认值是true;

maxPostSize POST方法能够提交的数据的最大大小,如果没有声明或者设置为小于等于0,则表示POST提交的数据大小是不限制的,默认值是2Megabytes.

protocol 设置处理请求的协议,默认是HTTP/1.1,即org.apache.coyote.http11.Http11Protocol,此外还 支持的协议有:

rg.apache.coyote.http11.Http11NioProtocol(通过NIO处理用户请求,可以提高系统性能), org.apache.coyote.http11.HttpAprProtocol。

roxyName/proxyPort 如果Web服务器使用了代理服务器,配置此参数意味着在调用request.getServerName的时候将会获取代理服务器的名称,

getServerPort()将会返回proxyPort。

redirectPort 如果Connector的配置是支持非SSL的请求,当一个SSL请求到来时,服务器会自动的将请求重定位到redirectPort。

URIEncoding URI字节转化成String的时候的编码方式,默认为ISO-8859-1,如果页面需要支持中文,一般可以将其设置为UTF-8或者GBK,GB2312。

useBodyEncodingForURI 如果设置为true,则会根据页面的编码决定URI的编码方式,默认是false。

Http/1.1 Connector提供的配置项:

acceptCount 等待队列的长度,默认值是100。

四,Engine和Host

Emgine:

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

</Engine>

这个应该不用展开叙述了,其中 defaultHost 用于指定访客在没有相应的虚拟主机时,Tomcat 默认选择的虚拟主机的名称。考虑如下的情形:假如有3个域名都 DNS 解析到你的服务器,比如 dog.com, www.dog.com, api.dog.com,当前你只配置了虚拟主机 dog.com 和 www.dog.com,那么当有个访客通过 api.dog.com 访问你的服务器时,Tomcat 就会依据 defaultHost 的设置返回其中一个虚拟主机运行的结果。实际应用中 defaultHost 应该设置为你的主力域名,比如 www.dog.com。

Host:

  1. <Host name="localhost"  appBase="webapps"
  2.             unpackWARs="true" autoDeploy="true">
  3.         <Alias>dog.com</Alias>
  4.         <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
  5.                prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
  6. </Host>

属性:

  • name:设置虚拟主机的域名,比如 localhost 表示本机名称,实际应用时应该填写具体域名,比如 www.dog.com 或者 dog.com,当然如果该虚拟主机是给内部人员访问的,也可以直接填写服务器的 ip 地址,比如 192.168.1.10。
  • autoDeploy:是否允许自动部署,默认值是 true,即表示 Tomcat 会自动检测 appBase 目录下面的文件变化从而自动应用到正在运行的 Web 应用程序。
  • unpackWARs:设置是否自动展开 war 压缩包再运行 Web 应用程序,默认值是 true。
  • appBase:设置 Web 应用程序组的路径。前面说过一个虚拟主机可以由多个 Web 应用程序构成,所以这里的 appBase 所指向的目录应该是准备用于存放这一组 Web 应用程序的目录,而不是具体某个 Web 应用程序的目录本身(即使该虚拟主机只由一个 Web 应用程序组成)。appBase 属性的值可以是相对于 Tomcat 安装目录的相对路径,也可以是绝对路径,需要注意的是该路径必须是 Tomcat 有权限访问的,通过 Arch Linux 源安装的 Tomcat 是通过 tomcat 用户运行的,因此创建一个新的 appBase 目录之后可以使用 chown 命令更改目录的所有者。

二,web.xml的配置

Web.xml是WEB应用的描述性文件,它的元素来自于Servlet的规范定义

web的文件包括两种:

  1. 默认:在tomcat/conf/web.xml
  2. 定制:WEB-INF/web.xml

一,ServletContext初始化参数

<context-param>
    <param-name></param-name>
    <param-value></param-value>
</context-param>

param-name:Servlet名称,要在Servlet中获取

param-value:初始化值

二,Servlet和Servlet-mapping映射

Servlet:

<servlet>
    <servlet-name>wql</servlet-name>
    <servlet-class>com.WQL.test</servlet-class>
    <init-param>
        <param-name>namespace</param-name>
        <param-value>q</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <enabled></enabled>
</servlet>

servlet-name:Servlet名称指定义

servlet-class:Servlet类路径

init-param:初始化Servlet类中的参数,param-name参数名,param-value参数值

load-on-startup:是否在Tomcat服务器启动时加载,小于o表示Tomcat启动时不加载Servlet,反之则加载

enabled:true处理Servlet请求,flase不处理任何Servlet请求

Servlet-mapping:

Servlet映射提供Http请求定位Servlet

<servlet-mapping>
    <servlet-name>wql</servlet-name>
    <url-pattern>/wql</url-pattern>
</servlet-mapping>

servlet-name:servlet名字

url-pattern:映射地址,可配多个

三,Filter和Filetr-mapping过滤器的配置

<filter>
    <filter-name></filter-name>
    <init-param>
        <param-name></param-name>
        <param-value></param-value>
    </init-param>
    <filter-class></filter-class>
</filter>

filter-name:过滤器名称

init-param:默认参数配置

filter-class:拦截之后要实现的Servlet类

Filetr-mapping:

<filter-mapping>
    <filter-name></filter-name>
    <url-pattern></url-pattern>
</filter-mapping>

filter-name:过滤器的名字,与Filter一致

url-pattern:拦截的url


路漫漫其修远兮,吾将上下而求索