Spring boot,Tomcat容器之间关系以及请求执行流程

上一篇讲完了spring cloud,Spring boot,Tomcat容器之间关系以及执行顺序,这次再继续讲当一个请求到达服务时,执行的流程:
首先我们得把Tomcat讲清楚:
在这里插入图片描述
综上所述,一个tomcat只包含一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但有多个Connector,这样一个服务可以处理多个连接。
多个Connector和一个Container就形成了一个Service,有了Service就可以对外提供服务了,但是Service要提供服务又必须提供一个宿主环境,那就非Server莫属了,所以整个tomcat的声明周期都由Server控制。
Tomcat中的六个容器:

容器 作用
Server容器 一个StandardServer类实例就表示一个Server容器,server是tomcat的顶级构成容器
Service容器 一个StandardService类实例就表示一个Service容器,Tomcat的次顶级容器,Service是这样一个集合:它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求。
Engine容器 一个StandardEngine类实例就表示一个Engine容器。Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名。当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理,Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理
Host容器 一个StandardHost类实例就表示一个Host容器,代表一个VirtualHost,虚拟主机,每个虚拟主机和某个网络域名Domain Name相匹配。每个虚拟主机下都可以部署(deploy)一个或者多个WebApp,每个Web App对应于一个Context,有一个Context path。当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理。匹配的方法是“最长匹配”,所以一个path==”“的Context将成为该Host的默认Context。所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配
Context容器 一个StandardContext类实例就表示一个Context容器。一个Context对应于一个Web Application,一个WebApplication由一个或者多个Servlet组成。Context在创建的时候将根据配置文件CATALINA_HOME/conf/web.xml和WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。当Context获得请求时,将在自己的映射表(mappingtable)中寻找相匹配的Servlet类。如果找到,则执行该类,获得请求的回应,并返回
Wrapper容器 一个StandardWrapper类实例就表示一个Wrapper容器,Wrapper容器负责管理一个Servlet,包括Servlet的装载、初始化、资源回收。Wrapper是最底层的容器,其不能在添加子容器了。Wrapper是一个接口,其标准实现类是StandardWrapper

Server,Service,Engine一目了然,然后Host容器里可能会有点费解,这里先对host解释下:我们知道,在我们访问一个网站时,我们需要在浏览器的地址栏输入一个网页地址,浏览器会试图将域名解析成IP,这个IP代表了连接到互联网的一台主机(Host)。在浏览器向主机发送的HTTP请求中,也包含了请求的Host信息:例如,www.baoidu.com。在最简单的情况下,一台主机只需要对应一个IP,提供一个web服务即可,这种情况下一个IP就对应一台物理主机(Physical Host)。然而,在多数情况下,一台主机不会只提供一个web服务,因而一台物理主机就需要虚拟出多台主机来,这就是Virtual Host。Virtual Host根据实现技术的不同可以分为基于名称的Virtual Host和基于IP的Virtual Host。
基于名称的Virtual Host
基于名称的Virtual Host,对于基于名称的Virtual Host来说,每一个Virtual Host对应一个域名,这些域名都解析到同一个IP下去,这样,这些Virtual Host就共享了这个IP对应的物理主机的资源
基于IP的Virtual Host
不同于基于名称的Virtual Host,在基于IP的Virtual Host中,可以将多个IP地址绑定到同一台物理主机上去,这个是怎么做到的呢?一个方式在物理主机上配置多块网卡,另一个就是通过Virtual Network Interfaces来实现,在Tomcat中配置基于IP的Virtual Host。
好的,说完了host,我们看下请求的流程:
在这里插入图片描述

Connector:Connector 用于接收请求并将请求封装成Request 和Response 来具体处理,最底层是使用Socket 来进行连接的, Request 和Response 是按照HTTP 协议来封装的,所以Connector 同时实现了TCP/IP 协议和HTTP 协议, Request 和Response 封装完之后交给Container 进行处理,Container 就是Servlet 的容器, Container 处理完之后返回给Connector,最后Connector 使用Socket 将处理结果返回给客户端,这样整个请求就处理完了。
在这里插入图片描述
一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户。
Tomcat有两个典型的Connector:

  • 一个直接侦听来自browser的http请求
  • 一个侦听来自其它WebServer的请求
    Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求。
    Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。
    请求流程:
    1、客户端发送请求:http://localhost:8080/wsota/wsota_index.jsp
    2、请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得
    3、 Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应
    4、 Engine获得请求localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机Host
    5、Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
    6、localhost Host获得请求/wsota/wsota_index.jsp,匹配它所拥有的所有Context
    7、Host匹配到路径为/wsota的Context(如果匹配不到就把该请求交给路径名为"“的Context去处理)
    8、path=”/wsota"的Context获得请求/wsota_index.jsp,在它的mapping table中寻找对应的servlet
    9、Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
    10、构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
    11、Context把执行完了之后的HttpServletResponse对象返回给Host
    12、Host把HttpServletResponse对象返回给Engine
    13、Engine把HttpServletResponse对象返回给Connector
    14、Connector把HttpServletResponse对象返回给客户browser

Tomcat的启动与类的具体实现

一个WEB应用对应一个context容器,也就是servlet运行时的负责管理servlet的容器。

添加一个web应用时将会创建一个StandardContext容器,并且给这个context容器设置必要的参数,url和path分别代表这个应用在tomcat中的访问路径和这个应用实际的物理路径,这两个参数与tomcat配置中的两个参数是一致的。
其中一个最重要的一个配置是ContextConfig,这个类会负责整个web应用配置的解析工作。

最后将这个context容器加入到父容器host中。

接下来会调用tomcat的start方法启动tomcat。

Tomcat的启动逻辑是基于观察者模式的,所有的容器都会继承Lifecycle接口,它管理着容器的整个生命周期,所有容器的修改和状态改变都会由它通知已经注册的观察者。

Tomcat启动的时序如下:
在这里插入图片描述

ContextConfig的init方法

当context容器初始状态设置Init时,添加到context容器的listener将会被调用。ContextConfig继承了LifecycleListener接口,它是在调用Tomcat.addWebapp时被加入到StandardContext容器中的。ContextConfig类会负责整个WEB应用的配置文件的解析工作。

ContextConfig的init方法将会主要完成一下工作:
创建用于解析XML配置文件的contextDigester对象
读取默认的context.xml文件,如果存在则解析它
读取默认的Host配置文件,如果存在则解析它
读取默认的Context自身的配置文件,如果存在则解析它
设置Context的DocBase

startInternal方法

ContextConfig的init方法完成后,Context容器会执行startInternal方法,这个方法包括如下几个部分:

创建读取资源文件的对象
创建ClassLoader对象
设置应用的工作目录
启动相关的辅助类,如logger,realm,resources等
修改启动状态,通知感兴趣的观察者
子容器的初始化
获取ServletContext并设置必要的参数
初始化“load on startuo”的Servlet

Web应用的初始化

web应用的初始化在14步,下面是该初始化的详细内容

WEB应用的初始化工作是在ContextConfig的configureStart方法中实现的,应用的初始化工作主要是解析web.xml文件,这个文件是一个WEB应用的入口。

Tomcat首先会找globalWebXml,这个文件的搜索路径是engine的工作目录下的org/apache/catalina/startup/NO-DEFAULT_XML或conf/web.xml。

接着会找hostWebXml,这个文件可能会在System.getProperty(“catalina.base”)/conf/$ {EngineName}/${HostName}/web.xml.default中。

接着寻找应用的配置文件examples/WEB-INF/web.xml,web.xml文件中的各个配置项将会被解析成相应的属性保存在WebXml对象中。

接下来会讲WebXml对象中的属性设置到context容器中,这里包括创建servlet对象,filter,listerner等,这些在WebXml的configureContext方法中。

以及下面是解析servlet的代码对象:

for (ServletDef servlet : servlets.values()) {
     
    Wrapper wrapper = context.createWrapper();  
    String jspFile = servlet.getJspFile();  
    if (jspFile != null) {
     
        wrapper.setJspFile(jspFile);  
    }  
    if (servlet.getLoadOnStartup() != null) {
     
        wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());  
    }  
    if (servlet.getEnabled() != null) {
     
        wrapper.setEnabled(servlet.getEnabled().booleanValue());  
    }  
    wrapper.setName(servlet.getServletName());  
    Map<String,String> params = servlet.getParameterMap();  
    for (Entry<String, String> entry : params.entrySet()) {
     
        wrapper.addInitParameter(entry.getKey(), entry.getValue());  
    }  
    wrapper.setRunAs(servlet.getRunAs());  
    Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();  
    for (SecurityRoleRef roleRef : roleRefs) {
     
        wrapper.addSecurityReference(roleRef.getName(), roleRef.getLink());  
    }  
    wrapper.setServletClass(servlet.getServletClass());  
    MultipartDef multipartdef = servlet.getMultipartDef();  
    if (multipartdef != null) {
     
        if (multipartdef.getMaxFileSize() != null &&  
            multipartdef.getMaxRequestSize()!= null &&  
            multipartdef.getFileSizeThreshold() != null) {
     
                wrapper.setMultipartConfigElement(new MultipartConfigElement(  
                                                      multipartdef.getLocation(),  
                                                      Long.parseLong(multipartdef.getMaxFileSize()),  
                                                  Long.parseLong(multipartdef.getMaxRequestSize()),  
                                                  Integer.parseInt(  
                                                  multipartdef.getFileSizeThreshold())));  
        } else {
     
        wrapper.setMultipartConfigElement(new MultipartConfigElement(  
                                              multipartdef.getLocation()));  
        }  
    }  
    if (servlet.getAsyncSupported() != null) {
     
        wrapper.setAsyncSupported(  
            servlet.getAsyncSupported().booleanValue());  
    }  
    context.addChild(wrapper)
  • 12
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot 启动内嵌 Tomcat 的过程可以分为以下几个步骤: 1. 配置 Spring Boot 应用程序的 pom.xml 文件,添加以下依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 2. 创建一个 Spring Boot 应用程序类,并在其 main 方法中调用 SpringApplication.run 方法,如下所示: ``` @SpringBootApplication public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 3. 在应用程序配置文件 application.properties 或 application.yml 中配置 Tomcat 服务器相关的属性,例如端口号、上下文路径等,如下所示: ``` # application.properties server.port=8080 server.servlet.context-path=/myapp ``` ``` # application.yml server: port: 8080 servlet: context-path: /myapp ``` 4. 使用 Spring Boot 提供的嵌入式 Tomcat 作为 Web 服务器。Spring Boot 会根据应用程序的配置自动配置 Tomcat 服务器,创建 TomcatEmbeddedServletContainerFactory 对象,并将其注入到 Spring 容器中。 5. 在应用程序启动过程中,Spring Boot 会扫描应用程序中所有的 @Controller、@RestController、@RequestMapping 等注解,并将其注册到 Tomcat 服务器中。 6. 当应用程序收到请求时,Tomcat 服务器会将请求转发给对应的 Controller 方法,Controller 方法会处理请求并返回响应,Tomcat 服务器将响应发送给客户端。 以上就是 Spring Boot 启动内嵌 Tomcat 的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值