SpringMVC中使用RedirectAttributes重定向传参,防止暴露参数,Tomcat 系统架构和原理解析

RedirectAttributes是SpringMVC3.1版本之后出来的一个功能,专门用于重定向之后还能带参数跳转的.

当我从jsp页面函数中带参数到controller层方法,方法执行完毕后返回到页面会显示出url地址参数信息,如果不想显示,可以考虑使用RedirectAttributes对象来重定向带参数

示例:

jsp页面函数执行

到Controller层执行完方法

返回到页面,url地址栏中带参数

修改后:

使用RedirectAttributes对象的addFlashAttribute()方法进行保存参数信息,跳转到另一个方法,最后返回页面

重定向到另一个方法,将之前的注解@RequestParam换成@ModelAttribute注解来获取参数信息

 返回到页面,url后面就不会显示出参数信息

Tomcat 系统架构和原理解析 - 简书 (jianshu.com)

1. 浏览器方问服务器的流程

 
image.png

 

注意:浏览器访问服务器使⽤的是Http协议,Http是应⽤层协议,⽤于定义数据通信的格式,具体的数据传输使⽤的是TCP/IP协议

2. Tomcat 请求总体流程

Tomcat是⼀个Http服务器(能够接收并且处理http请求,所以tomcat是⼀个http服务器)

 

 
image.png

3.Tomcat Servlet容器处理流程

当用户请求某个URL资源时

  1. HTTP服务器会把请求信息适用ServletRequest对象封装起来
  2. 进一步去调用Servlet容器中某个具体的Servlet
  3. 在第二步中,Servlet容器拿到请求后,根据Url和Servlet的映射关系,找到相应的Servlet
  4. 如果Servlet还没有被加载,反射创建这个Servlet,并调用Servlet的init方法完成初始化
  5. 接着调用直这个具体的Servlet的service方法来处理请求,请求处理结果适用ServletResponse对象封装
  6. 把ServletResponse对象返回给Http服务器,Http服务器会把响应发送给客户端


     
    image.png

4.Tomcat 系统总体架构

通过上⾯的讲解,我们发现tomcat有两个⾮常重要的功能需要完成

  1. 和客户端浏览器进行交互,进行Socket通信,将字节流和Request/Response对象进行转换
  2. Servlet容器处理逻辑
     
    image.png

    Tomcat设计了两个核心组件连接器(Connector)容器(Container) 来完成Tomcat的两大核心功能。
    连接器,负责对外交流:处理Socket连接,负责网络字节流和Requst/Response对象的转换
    容器,负责内部处理:加载和管理Servlet,以及具体处理Request请求。

5.Tomcat 连接器组件Coyote

5.1 Coyote简介

Coyote 是Tomcat 中连接器的组件名称 , 是对外的接⼝。客户端通过Coyote与服务器建⽴连接、发送请求并接受响应 。

  1. Coyote封装了底层网络通信
  2. Coyotte使Catalina容器与具体的请求协议以及IO操作完全解耦
  3. Coyote 将Socket输入转换封装为Request对象,进一步封装后交由Catalina容器进行处理,处理请求完成后,Catalina通过Coyote提供的Response对象将结果写入输入流
  4. Coyote 负责的具体协议(应用层)和IO(传输层)相关内容


     
    image.png
5.2 Coyote组件
  1. EndPoint :Endpoint是Coyote的通信端点,即通信监听的接口,是具体Socket接受和发送的处理器,是对传输层的抽象,因此EndPoint用来实现TCP/IP协议
  2. Processor:Processor是Coyote协议处理接口,如果说endpoint用来实现tcp/ip协议,那么Processor用来实现Http协议,Processor接受来自于Endpoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理,Processor是对应用层协议的抽象
  3. ProtocolHandler:Coyote协议接口,通过Endpoint 和 Processor ,实现针对具体协议的处理能力。
  4. Adapter:由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的Request类来封装这些请求。但是这个Request对象不是标准的ServletRequest,不能⽤Tomcat Request作为参数来调⽤容器。Tomcat设计者的解决⽅案是引⼊CoyoteAdapter,这是适配器模式的经典运⽤,连接器调⽤CoyoteAdapter的Sevice⽅法,传⼊的是Tomcat Request对象,CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调⽤容器。
     
    image.png

     
    image.png

6.Tomcat Servlet容器 Catalina

6.1 Tomcat模块分层结构图及Catalina位置

Tomcat是由一系列可配置的(conf/sever.xml)的组件构成的Web容器,而Catalina是Tomcat的servlet容器。
从另⼀个⻆度来说,Tomcat 本质上就是⼀款 Servlet 容器, 因为 Catalina 才是 Tomcat 的核⼼ , 其他模块都是为Catalina 提供⽀撑的。

 
image.png

 

6.2 Servlet容器 Catalina的结构

可以认为整个Tomcat就是一个Catalina实例,Tomcat启动的时候会初始化这个实例,Catalina实例通过加载server.xml完成其他实例的创建,创建并管理多个服务,每个服务又可以有多个Connector和Container。
⼀个Catalina实例(容器)
⼀个 Server实例(容器)
多个Service实例(容器)
每⼀个Service实例下可以有多个Connector实例和⼀个Container实例

 

 
image.png

 

 
image.png
  1. Catalina
    负责解析Tomcat配置文件(serve.xml),以此来创建服务器Server组件并进行管理。
  2. Server
    服务器表示整个Catalina Servlet容器以及其他组件,负责组装并启动Servlet引擎,Tomcat连接器。Server通过实现Lifecycle接口,提供一个优雅的启动和关闭整个系统的方式。
  3. Service
    服务是Server内部的组件,一个Server包含多个Sevice。它将若干的Connector组件绑定到一个Container。
  4. Container
    容器,负责处理用户的servlet请求,并返回对象给web用户的模块。
6.3 Container 组件的具体结构

Container组件下有几种具体的组件,分别是 Engine,Host,Context和Wrapper。这四种组件是父子关系。Tomcat'通过一种分层的架构,使得Servlet容器具有很好的灵活性。

  1. Engine
    表示整个Catalina的Servlet引擎,用来管理多个虚拟站点,一个Service最多只能有一个Engine,但是一个引擎可以包含多个Host
  2. Host
    代表一个虚拟主机,或者说一个站点。可以给Tomcat配置多个虚拟主机地址,而一个虚拟主机下可包含多个Context。
  3. Context
    表示一个Web应用程序,一个Web应用可包含多个Wrapper。
    4.Wrapper
    表示一个Servlet,Wrapper作为容器中的最底层,不能包含子容器。

上述组件配置其实就体现在conf/server.xml

主要标签结构如下

<!--
 Server 根元素,创建⼀个Server实例,⼦标签有 Listener、GlobalNamingResources、Service
-->
<Server>
 <!--定义监听器-->
 <Listener/>
 <!--定义服务器的全局JNDI资源 -->
 <GlobalNamingResources/>
 <!--
 定义⼀个Service服务,⼀个Server标签可以有多个Service服务实例
 -->
 <Service/>
</Server>

Server标签

<!--
 port:关闭服务器的监听端⼝
 shutdown:关闭服务器的指令字符串
-->
<Server port="8005" shutdown="SHUTDOWN">
 <!-- 以⽇志形式输出服务器 、操作系统、JVM的版本信息 -->
 <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
 <!-- Security listener. Documentation at /docs/config/listeners.html
 <Listener className="org.apache.catalina.security.SecurityListener" />
 -->
 <!--APR library loader. Documentation at /docs/apr.html -->
 <!-- 加载(服务器启动) 和 销毁 (服务器停⽌) APR。 如果找不到APR库, 则会输出⽇志, 并
不影响 Tomcat启动 -->
 <Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" />
 <!-- Prevent memory leaks due to use of particular java/javax APIs-->
 <!-- 避免JRE内存泄漏问题 -->
 <Listener
className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
 <!-- 加载(服务器启动) 和 销毁(服务器停⽌) 全局命名服务 -->
 <Listener
className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
 <!-- 在Context停⽌时重建 Executor 池中的线程, 以避免ThreadLocal 相关的内存泄漏 -->
 <Listener
className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
 
 
 <!-- Global JNDI resources
 Documentation at /docs/jndi-resources-howto.html
 GlobalNamingResources 中定义了全局命名服务
 -->
 <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>
 <!-- A "Service" is a collection of one or more "Connectors" that share
 a single "Container" Note: A "Service" is not itself a "Container",
 so you may not define subcomponents such as "Valves" at this level.
 Documentation at /docs/config/service.html
 -->
 <Service name="Catalina">
 ...
 </Service>
</Server>

Service标签

<!--
 该标签⽤于创建 Service 实例,默认使⽤ org.apache.catalina.core.StandardService。
 默认情况下,Tomcat 仅指定了Service 的名称, 值为 "Catalina"。
 Service ⼦标签为 : Listener、Executor、Connector、Engine,
 其中:
 Listener ⽤于为Service添加⽣命周期监听器,
 Executor ⽤于配置Service 共享线程池,
 Connector ⽤于配置Service 包含的链接器,
 Engine ⽤于配置Service中链接器对应的Servlet 容器引擎
-->
<Service name="Catalina">
 ...
</Service>

Executor标签

<!--
Connector 标签
Connector 标签⽤于创建链接器实例
默认情况下,server.xml 配置了两个链接器,⼀个⽀持HTTP协议,⼀个⽀持AJP协议
⼤多数情况下,我们并不需要新增链接器配置,只是根据需要对已有链接器进⾏优化
 默认情况下,Service 并未添加共享线程池配置。 如果我们想添加⼀个线程池, 可以在
<Service> 下添加如下配置:
 name:线程池名称,⽤于 Connector中指定
 namePrefix:所创建的每个线程的名称前缀,⼀个单独的线程名称为
namePrefix+threadNumber
 maxThreads:池中最⼤线程数
 minSpareThreads:活跃线程数,也就是核⼼池线程数,这些线程不会被销毁,会⼀直存在
 maxIdleTime:线程空闲时间,超过该时间后,空闲线程会被销毁,默认值为6000(1分钟),单位
毫秒
 maxQueueSize:在被执⾏前最⼤线程排队数⽬,默认为Int的最⼤值,也就是⼴义的⽆限。除⾮特
殊情况,这个值 不需要更改,否则会有请求不会被处理的情况发⽣
 prestartminSpareThreads:启动线程池时是否启动 minSpareThreads部分线程。默认值为
false,即不启动
 threadPriority:线程池中线程优先级,默认值为5,值从1到10
 className:线程池实现类,未指定情况下,默认实现类为 
org.apache.catalina.core.StandardThreadExecutor。如果想使⽤⾃定义线程池⾸先需要实现
org.apache.catalina.Executor接⼝
-->
<Executor name="commonThreadPool"
 namePrefix="thread-exec-"
 maxThreads="200"
 minSpareThreads="100"
 maxIdleTime="60000"
 maxQueueSize="Integer.MAX_VALUE"
 prestartminSpareThreads="false"
 threadPriority="5"
 className="org.apache.catalina.core.StandardThreadExecutor"/>

Connector 标签
默认情况下,server.xml 配置了两个链接器,⼀个⽀持HTTP协议,⼀个⽀持AJP协议

<!--
port:
 端⼝号,Connector ⽤于创建服务端Socket 并进⾏监听, 以等待客户端请求链接。如果该属性设置
为0, Tomcat将会随机选择⼀个可⽤的端⼝号给当前Connector 使⽤
protocol:
 当前Connector ⽀持的访问协议。 默认为 HTTP/1.1 , 并采⽤⾃动切换机制选择⼀个基于 JAVA
NIO 的链接器或者基于本地APR的链接器(根据本地是否含有Tomcat的本地库判定)
connectionTimeOut:
Connector 接收链接后的等待超时时间, 单位为 毫秒。 -1 表示不超时。
redirectPort:
 当前Connector 不⽀持SSL请求, 接收到了⼀个请求, 并且也符合security-constraint 约束,
需要SSL传输,Catalina⾃动将请求重定向到指定的端⼝。
executor:
 指定共享线程池的名称, 也可以通过maxThreads、minSpareThreads 等属性配置内部线程池。
可以使⽤共享线程池
Engine 标签
Engine 表示 Servlet 引擎
Host 标签
Host 标签⽤于配置⼀个虚拟主机
URIEncoding:
 ⽤于指定编码URI的字符编码, Tomcat8.x版本默认的编码为 UTF-8 , Tomcat7.x版本默认为ISO�8859-1
-->
<!--org.apache.coyote.http11.Http11NioProtocol , ⾮阻塞式 Java NIO 链接器-->
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

可以使⽤共享线程池

<Connector port="8080" 
 protocol="HTTP/1.1"
 executor="commonThreadPool"
 maxThreads="1000" 
 minSpareThreads="100" 
 acceptCount="1000" 
 maxConnections="1000" 
 connectionTimeout="20000"
 compression="on" 
 compressionMinSize="2048" 
 disableUploadTimeout="true" 
 redirectPort="8443" 
 URIEncoding="UTF-8" />

Engine 标签
Engine 表示 Servlet 引擎

<!--
name: ⽤于指定Engine 的名称, 默认为Catalina
defaultHost:默认使⽤的虚拟主机名称, 当客户端请求指向的主机⽆效时, 将交由默认的虚拟主机处
理, 默认为localhost
-->
<Engine name="Catalina" defaultHost="localhost">
 ...
</Engine>

Host 标签
Host 标签⽤于配置⼀个虚拟主机

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

Context 标签
Context 标签⽤于配置⼀个Web应⽤,如下:

<Host name="www.abc.com" appBase="webapps" unpackWARs="true"
autoDeploy="true">
<!--
 docBase:Web应⽤⽬录或者War包的部署路径。可以是绝对路径,也可以是相对于 Host appBase的
相对路径。
 path:Web应⽤的Context 路径。如果我们Host名为localhost, 则该web应⽤访问的根路径为: 
 http://localhost:8080/web_demo。
-->
 <Context docBase="/Users/yingdian/web_demo" path="/web3"></Context> 
 
 <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" />
</Host>

7.HTTP请求流程

打开 tomcat/conf 目录下的 server.xml 文件来分析一个http://localhost:8080/docs/api 请求。

  1. 连接器监听的端口8080.因为请求端口和监听端口一致,连接器接受该请求。
  2. 因为引擎的默认虚拟主机是localhost,并且虚拟主机目录是webapps,所以请求找到tomcat/webapps目录。
  3. 解析docs是web程序的应用名,也就是context。此时请求继续从webapps目录找到docs目录。有的时候我们也会将应用名省略。
  4. 解析的api是具体的业务逻辑地址。此时需要从docs/WEB-INF/web.xml 找到映射关系,最后调用具体的函数。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">

  <Service name="Catalina">

    <!-- 连接器监听端口是 8080,默认通讯协议是 HTTP/1.1 -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
               
    <!-- 名字为 Catalina 的引擎,其默认的虚拟主机是 localhost -->
    <Engine name="Catalina" defaultHost="localhost">

      <!-- 名字为 localhost 的虚拟主机,其目录是 webapps-->
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

      </Host>
    </Engine>
  </Service>
</Server>

Tomcat 的工作原理万字总结,这回终于搞懂了! - 知乎 (zhihu.com)

前言

如果同一台电脑上同时装了两个Tomcat并且都启动了有相同的网页,当我们访问其中的网页,输入URL后,Tomcat如何判断我请求的是哪个服务器的网页呢?它将用哪个为我服务呢?

SpringBoot 就像一条巨蟒,慢慢缠绕着我们,使我们麻痹。不得不承认,使用了 SpringBoot 确实提高了工作效率,但同时也让我们遗忘了很多技能。刚入社会的时候,我还是通过 Tomcat 手动部署 JavaWeb 项目,还经常对 Tomcat 进行性能调优。除此之外,还需要自己理清楚各 Jar 之间的关系,以避免 Jar 丢失和各版本冲突导致服务启动异常的问题。到如今,这些繁琐而又重复的工作已经统统交给 SpringBoot 处理,我们可以把更多的精力放在业务逻辑上。但是,清楚 Tomcat 的工作原理和处理请求流程和分析 Spring 框架源码一样的重要。至少面试官特别喜欢问这些底层原理和设计思路。希望这篇文章能给你一些帮助。

Tomcat 整体架构

Tomcat 是一个免费的、开源的、轻量级的 Web 应用服务器。适合在并发量不是很高的中小企业项目中使用。

文件目录结构

以下是 Tomcat 8 主要目录结构

 

 

功能组件结构

Tomcat 的核心功能有两个,分别是负责接收和反馈外部请求的连接器 Connector,和负责处理请求的容器 Container。其中连接器和容器相辅相成,一起构成了基本的 web 服务 Service。每个 Tomcat 服务器可以管理多个 Service。

 

 

 

 

Tomcat 连接器核心原理

Tomcat 连接器框架——Coyote

连接器核心功能

一、监听网络端口,接收和响应网络请求。

二、网络字节流处理。将收到的网络字节流转换成 Tomcat Request 再转成标准的 ServletRequest 给容器,同时将容器传来的 ServletResponse 转成 Tomcat Response 再转成网络字节流。

连接器模块设计

为满足连接器的两个核心功能,我们需要一个通讯端点来监听端口;需要一个处理器来处理网络字节流;最后还需要一个适配器将处理后的结果转成容器需要的结构。

 

 

对应的源码包路径 org.apache.coyote 。对应的结构图如下

 

 

Tomcat 容器核心原理

Tomcat 容器框架——Catalina

容器结构分析

每个 Service 会包含一个容器。容器由一个引擎可以管理多个虚拟主机。每个虚拟主机可以管理多个 Web 应用。每个 Web 应用会有多个 Servlet 包装器。Engine、Host、Context 和 Wrapper,四个容器之间属于父子关系。

 

 

对应的源码包路径 org.apache.coyote 。对应的结构图如下

 

 

容器请求处理

容器的请求处理过程就是在 Engine、Host、Context 和 Wrapper 这四个容器之间层层调用,最后在 Servlet 中执行对应的业务逻辑。各容器都会有一个通道 Pipeline,每个通道上都会有一个 Basic Valve(如StandardEngineValve), 类似一个闸门用来处理 Request 和 Response 。其流程图如下。

 

 

Tomcat 请求处理流程

上面的知识点已经零零碎碎地介绍了一个 Tomcat 是如何处理一个请求。简单理解就是连接器的处理流程 + 容器的处理流程 = Tomcat 处理流程。哈!那么问题来了,Tomcat 是如何通过请求路径找到对应的虚拟站点?是如何找到对应的 Servlet 呢?

映射器功能介绍

这里需要引入一个上面没有介绍的组件 Mapper。顾名思义,其作用是提供请求路径的路由映射。根据请求URL地址匹配是由哪个容器来处理。其中每个容器都会它自己对应的Mapper,如 MappedHost。不知道大家有没有回忆起被 Mapper class not found 支配的恐惧。在以前,每写一个完整的功能,都需要在 web.xml 配置映射规则,当文件越来越庞大的时候,各个问题随着也会出现

HTTP请求流程

打开 tomcat/conf 目录下的 server.xml 文件来分析一个localhost:8080/docs/api 请求。

第一步:连接器监听的端口是8080。由于请求的端口和监听的端口一致,连接器接受了该请求。

第二步:因为引擎的默认虚拟主机是 localhost,并且虚拟主机的目录是webapps。所以请求找到了 tomcat/webapps 目录。

第三步:解析的 docs 是 web 程序的应用名,也就是 context。此时请求继续从 webapps 目录下找 docs 目录。有的时候我们也会把应用名省略。

第四步:解析的 api 是具体的业务逻辑地址。此时需要从 docs/WEB-INF/web.xml 中找映射关系,最后调用具体的函数。

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">

  <Service name="Catalina">

    <!-- 连接器监听端口是 8080,默认通讯协议是 HTTP/1.1 -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
               
    <!-- 名字为 Catalina 的引擎,其默认的虚拟主机是 localhost -->
    <Engine name="Catalina" defaultHost="localhost">

      <!-- 名字为 localhost 的虚拟主机,其目录是 webapps-->
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

      </Host>
    </Engine>
  </Service>
</Server>

SpringBoot 如何启动内嵌的 Tomcat

SpringBoot 一键启动服务的功能,让有很多刚入社会的朋友都忘记 Tomcat 是啥。随着硬件的性能越来越高,普通中小项目都可以直接用内置 Tomcat 启动。但是有些大一点的项目可能会用到 Tomcat 集群和调优,内置的 Tomcat 就不一定能满足需求了。

我们先从源码中分析 SpringBoot 是如何启动 Tomcat,以下是 SpringBoot 2.x 的代码。

代码从 main 方法开始,执行 run 方法启动项目。

SpringApplication.run

从 run 方法点进去,找到刷新应用上下文的方法。

this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);

从 refreshContext 方法点进去,找 refresh 方法。并一层层往上找其父类的方法。

this.refresh(context);

在 AbstractApplicationContext 类的 refresh 方法中,有一行调用子容器刷新的逻辑。

this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();

从 onRefresh 方法点进去,找到 ServletWebServerApplicationContext 的实现方法。在这里终于看到了希望。

protected void onRefresh() {
    super.onRefresh();

    try {
        this.createWebServer();
    } catch (Throwable var2) {
        throw new ApplicationContextException("Unable to start web server", var2);
    }
}

从 createWebServer 方法点进去,找到从工厂类中获取 WebServer的代码。

if (webServer == null && servletContext == null) {
    ServletWebServerFactory factory = this.getWebServerFactory();
    // 获取 web server 
    this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
} else if (servletContext != null) {
    try {
        // 启动 web server
        this.getSelfInitializer().onStartup(servletContext);
    } catch (ServletException var4) {
        throw new ApplicationContextException("Cannot initialize servlet context", var4);
    }
}

从 getWebServer 方法点进去,找到 TomcatServletWebServerFactory 的实现方法,与之对应的还有 Jetty 和 Undertow。这里配置了基本的连接器、引擎、虚拟站点等配置。

public WebServer getWebServer(ServletContextInitializer... initializers) {
    Tomcat tomcat = new Tomcat();
    File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    Connector connector = new Connector(this.protocol);
    tomcat.getService().addConnector(connector);
    this.customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    this.configureEngine(tomcat.getEngine());
    Iterator var5 = this.additionalTomcatConnectors.iterator();

    while(var5.hasNext()) {
        Connector additionalConnector = (Connector)var5.next();
        tomcat.getService().addConnector(additionalConnector);
    }

    this.prepareContext(tomcat.getHost(), initializers);
    return this.getTomcatWebServer(tomcat);
}

 

动图封面
 

 

服务启动后会打印日志

o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8900 (http)
o.apache.catalina.core.StandardService   : Starting service [Tomcat]
org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.34
o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal ...
o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 16858 ms

END

作者:ITDragon龙
链接:cnblogs.com/itdragon/p/
来源:cnblogs

下面是 Tomcat Server处理一个HTTP请求的过程

 

 

1、用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。

2、Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。

3、Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。

4、Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。

5、path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。

6、构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost().执行业务逻辑、数据存储等程序。

7、Context把执行完之后的HttpServletResponse对象返回给Host。

8、Host把HttpServletResponse对象返回给Engine。

9、Engine把HttpServletResponse对象返回Connector。

10、Connector把HttpServletResponse对象返回给客户Browser。

posted @ 2022-11-30 19:33  CharyGao  阅读(786)  评论(0)    收藏  举报