Tomcat到Servlet再到DispatcherServlet

前言

写这篇文章的初衷其实是上一篇文章之后的想法,在TCP/IP五层模型视角下的浏览器请求中我以TCP/IP五层模型的视角分析了浏览器请求的传输过程,浏览器输入的url经过http封装后到达服务端TCP层后,得到的是个http请求,那么在服务端怎么对这个消息进行处理并返回响应?

先上结论,Tomact的Connector会监听端口,接受TCP请求并产生一个线程来处理这个请求,把产生的 Request 和 Response 对象传给后续步骤,最后Connector会返回HttpServletResponse,然后响应从五层模型原路返回浏览器。

一、Tomcat

https://blog.csdn.net/qq_38682952/article/details/81092446

Tomcat是一个JSP/Servlet容器。Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户下被普遍使用,是开发和调试JSP 程序的首选。负责处理客户请求,把请求传送给Servlet并把结果返回给客户。
img

请求到tomcat后,交给内部的servlet,servlet需要与请求url映射,servlet容器创建HttpRequest对象和HttpResponse对象HttpResponse对象,调用HttpServlet对象的service方法,根据请求得到响应并返回客户端。

到了SpringMVC时代,dispatcherservlet相当于servlet,所有请求都到这,然后根据处理器映射器找controller(@RequestMapping注解,实现指定控制器可以处理哪些URL请求),处理请求并返回响应。

1.tomcat架构和组件

img

由上图可看出Tomca的心脏是两个组件:Connector和Container(Engine,Host,Context,Wrapper)。一个Container可以选择多个Connecter,多个Connector和一个Container就形成了一个Service。Service可以对外提供服务,而Server服务器控制整个Tomcat的生命周期。

1、Server组件
各Server的定义不能使用同一个端口,这意味着如果在同一个物理机上启动了多个Server实例,必须配置它们使用不同的端口。

最高的组件就是 Server,而控制 Server 的是 Startup,也就是您启动和关闭 Tomcat。其中可以包含一个或者多个Service元素。

2.Service组件
主要用于关联一个引擎和与此引擎相关的连接器,每个连接器通过一个特定的端口和协议接收入站请求交将其转发至关联的引擎进行处理。包含一个Engine元素,以及一个或者个多个Connector元素,这些Connector共享同一个Engine元素,负责处理所有Connector所获得的客户请求。

3.Connector组件
一个Connecter将在某个指定的端口上侦听客户请求,接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理Engine(Container中的一部分),从Engine出获得响应并返回客户

4.Container组件
Container是容器的父接口,该容器的设计用的是典型的责任链的设计模式,它由四个自容器组件构成,分别是Engine、Host、Context、Wrapper。这四个组件是负责关系,存在包含关系。通常一个Servlet class对应一个Wrapper,如果有多个Servlet定义多个Wrapper,如果有多个Wrapper就要定义一个更高的Container,如Context。Context 还可以定义在父容器 Host 中,Host 不是必须的,但是要运行 war 程序,就必须要 Host,因为 war 中必有 web.xml 文件,这个文件的解析就需要 Host 了,如果要有多个 Host 就要定义一个 top 容器 Engine 了。而 Engine 没有父容器了,一个 Engine 代表一个完整的 Servlet 引擎。

1.Engine 容器
Engine 容器比较简单,它只定义了一些基本的关联关系,Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名
当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理,Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理。

2.Host 容器
Host 是 Engine 的字容器,一个 Host 在 Engine 中代表一个虚拟主机,这个虚拟主机的作用就是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们。它的子容器通常是 Context,它除了关联子容器外,还有就是保存一个主机应该有的信息。一个虚拟主机下都可以部署一个或者多个Web App,每个Web App对应于一个Context(每个Context下可有多个Wrapper(Servlet)),当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理。

3.Context 容器
Context 代表 Servlet 的 Context,它具备了 Servlet 运行的基本环境,理论上只要有 Context 就能运行 Servlet 了。简单的 Tomcat 可以没有 Engine 和 Host。Context 最重要的功能就是管理它里面的 Servlet 实例,Servlet 实例在 Context 中是以 Wrapper 出现的,还有一点就是 Context 如何才能找到正确的 Servlet 来执行它呢? Tomcat5 以前是通过一个 Mapper 类来管理的,Tomcat5 以后这个功能被移到了 request 中,在前面的时序图中就可以发现获取子容器都是通过 request 来分配的。一个Context对应于一个Web Application,一个Web Application由一个或者多个Servlet组成。

4.Wrapper 容器
Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。

总结一下tomcat启动过程:

Tomcat 先根据/conf/server.xml 下的配置启动Server,再加载Service,对于与Engine相匹配的Host,每个Host 下面都有一个或多个ContextWeb Application 对应一个Context,每个Web Application 由一个或多个Servlet 组成。当一个Web Application 被初始化的时候,它将用自己的ClassLoader 对象载入部署配置文件web.xml 中定义的每个Servlet 类。每个被载入的Servlet 类都有一个名字,且被填入该Context 的映射表(mapping table)中(Servlet的Mapping映射),和某种URL 路径对应。当该Context 获得请求时,将查询mapping table,找到被请求的Servlet,并执行以获得请求响应。

2.tomcat处理HTTP请求过程

tomcat实际是运行在jvm中的一个进程。他是一个在java项目与jvm之间的中间容器。我们的web项目没有入口方法(main方法)意味着web项目中的方法不会自动运行起来。这样,我们想想也知道,我们把web项目部署进tomcat的webapp中的目的是很明确的,那就是希望tomcat去调用我们写好的方法去为客户端返回需要的资源和数据。对于tomcat而言,它并不知道我们会有什么样的方法,这些都只是在项目被部署进webapp下后才确定的,由此分析,必然用到了java的反射来实现类的动态加载、实例化、获取方法、调用方法。

第一步:用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。
第二步:Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。
第三步:Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。
第四步:Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。
第五步:path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。
第六步:构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost().执行业务逻辑、数据存储等程序。
第七步:Context把执行完之后的HttpServletResponse对象返回给Host。
第八步:Host把HttpServletResponse对象返回给Engine。
第九步:Engine把HttpServletResponse对象返回Connector。
第十步:Connector把HttpServletResponse对象返回给客户Browser


3.总结:

1、Connector负责监听端口,接受浏览器来的tcp连接请求,创建一个 Request 和 Response 对象、

2、Engine收到请求后匹配一个Host

3、Host得到后匹配Context(相当于Servlet的容器),

4、Context得到请求根据Mapping映射找到相对应的Servlet

5、Servlet执行业务逻辑后,Context返回HttpServletResponse给Host、在返回Engine、再回Connector、返回客户端浏览器。

二、Servlet和Tomcat的关系(JAVA Web时代)

https://blog.csdn.net/bell_love/article/details/105667638

Tomcat作为Servlet容器,当然也可以当作web服务器直接使用,负责把接收和返回http请求。
这里写图片描述
下面,我们通过一个更细致的时序图来看一下具体工作过程:
这里写图片描述

从上图我们看出一个Http的具体处理流程:

  1. Web客户向Servlet容器(Tomcat)发出Http请求
  2. Servlet容器分析客户的请求信息
  3. Servlet容器创建一个HttpRequest对象,将客户请求的信息封装到这个对象中
  4. Servlet容器创建一个HttpResponse对象
  5. Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet对象
  6. HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息
  7. HttpServlet调用HttpResponse对象的有关方法,生成响应数据
  8. Servlet容器把HttpServlet的响应结果传给Web客户

其中,Tomcat的流程可以再细化为Connector、Engine、Host、Context、Wrapper等。

在这里插入图片描述

1.编写一个Servlet程序

Sun在API中提供一个接口叫做:Servlet,开发一个Servlet程序需要完成两个小步骤:

  1. 编写一个类,实现servlet接口;
  2. 把开发好的Java类部署到web服务器(tomcat)上。

把实现了Servlet接口的Java程序叫做,Servlet

在这里插入图片描述

1.编写一个普通类
2.实现Servlet接口,这里我们直接继承HttpServlet(HttpServlet实现了Servlet接口

public class HelloServlet extends HttpServlet {

    //get post只是请求实现的不同方式,所有这里两个丰富可以相互调用,业务逻辑是相同的
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doget");
        PrintWriter writer = resp.getWriter();//响应流
        writer.print("hello,servlet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

image-20210329202506910

2.编写Servlet的映射(Mapping)

为什么需要映射?
我们写的是Java程序,但是需要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给它一个浏览器能够访问的路径。映射指的是将请求(url路径)映射到对应的Servlet实例。

Tomcat下Servlet的配置文件:web.xml (JavaWeb时代)

web.xml的作用是配置Http和Servlet之间的映射关系、filter、context参数等。这样通过这份约定的配置文件,Tomcat可以把Http请求映射到不同的Servlet实例上。所以,在Servlet时代的web.xml中,会有很多的项配置。

image-20210329202735269

3.ServletContext

https://www.jianshu.com/p/31d27181d542

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用;

说起ServletContext,一些人会产生误解,以为一个servlet对应一个ServletContext。其实不是这样的,事实是一个web应用对应一个ServletContext,所以ServletContext的作用范围是整个应用,明确这点很重要,这是基础中的基础。

我曾经想,为什么不起名叫WebContext或者ApplicationContext或者WebApplicationContext?这样见名知意多好。后来我想这也可能是有历史原因的:最初的客户端-服务端的架构模型非常简单,服务端运行着一些servlet用来处理客户端的请求。那个时候服务器很轻量级,运行一个应用,应用就由一堆servlet组成。所以这样简单的服务器也被称作servlet容器,主要作用就是运行servlet的。那么提供给应用的上下文就叫做ServletContext。(这个纯属个人意淫_,不对勿喷)

一个web应用对应一个ServletContext实例,这个实例是应用部署启动后,servlet容器为应用创建的。ServletContext实例包含了所有servlet共享的资源信息。通过提供一组方法给servlet使用,用来和servlet容器通讯,比如获取文件的MIME类型、分发请求、记录日志等。

这里需要注意一点,如果你的应用是分布式部署的,那么每台服务器实例上部署的应用实例都各自拥有一个ServletContext实例。

img

共享数据

我在这个Servlet中保存的数据,可以在另外一个servlet中拿到;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        //this.getInitParameter()   初始化参数
        //this.getServletConfig()   Servlet配置
        //this.getServletContext()  Servlet上下文
        ServletContext context = this.getServletContext();

        String username = "秦疆"; //数据
        context.setAttribute("username",username); //将一个数据保存在了ServletContext中,名字为:username 。值 username

    }

}
public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String username = (String) context.getAttribute("username");

        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().print("名字"+username);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

4.HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器, HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息

5.HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest
对象,代表响应的一个HttpServletResponse;
  • 如果要获取客户端请求过来的参数:找HttpServletRequest
  • 如果要给客户端响应一些信息:找HttpServletResponse

三、SpringMVC和Tomcat关系(SpringMVC时代)

https://blog.csdn.net/achenyuan/article/details/77246395

1.SpringMVC和Tomcat的职责

SpringMVC、Tomcat是怎样完成一次Http请求的?

tomcat把请求分配给springmvc,具体业务逻辑由springmvc执行

SpringMVC和Tomcat的结合点是Servlet。其实SpringMVC的DispatchServlet实现了HttpServlet,那么SpringMVC在Tomcat看来,其实就是一个Servlet。

2.SpringMVC的DispatchServlet

SpringMVC也是Servlet的实现,只不过SpringMVC增加了一个DispatchServlet,所有的http请求都是映射到这个Servlet上,请求进入到这个Servlet中之后,就算进入到了框架之中了,由这个Servlet来统一的分配http请求到各个Controller,接下来的事情大家就清楚了。

流程:

1.所有的http请求到DispatcheerServlet

2.处理器映射器HandlerMapping找Controller。SpringMVC通过使用@RequestMapping注解,实现指定控制器可以处理哪些URL请求。(Java Web时代写多个Servlet,每个Servlet都要Mapping映射)

3.请求Controller执行并返回
在这里插入图片描述

  • 12
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值