• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    tomcat何时写回响应数据报的详析

    疑问的产生

    这个疑问是我在写文件下载的时候产生的,我是用HttpServletResponse获取到Outputstream,然后利用OutputStream直接写数据的。当时我就想这个OutputStream是不是就是对应的Socket连接的OutputStream。即是不是的程序在用stream写的时候,数据也同时在发?

    Response的OutputStream把数据写到哪去?

    于是我看了下HttpServletResponse的getOutputStream方法,看看它注释是怎么说的。

    /**
      * Returns a {@link ServletOutputStream} suitable for writing binary 
      * data in the response. The servlet container does not encode the
      * binary data. 
      *
      * <p> Calling flush() on the ServletOutputStream commits the response.
      *
      * Either this method or {@link #getWriter} may 
      * be called to write the body, not both, except when {@link #reset}
      * has been called.
      *
      * @return a {@link ServletOutputStream} for writing binary data 
      *
      * @exception IllegalStateException if the <code>getWriter</code> method
      * has been called on this response
      *
      * @exception IOException if an input or output exception occurred
      *
      * @see #getWriter
      * @see #reset
      */
     public ServletOutputStream getOutputStream() throws IOException;

    以上,注释有说明是OutputStream是用来写响应body内容的,也有提到flush()方法,说明肯定是有缓冲的,所以应该不是直接操作socket写数据。我猜测应该是有一个字节数组用来暂时存储,然后统一flush。但是还是不太确定,于是简单翻阅了下tomcat源码。

    找到ServletOutputStream的实现类CoyoteOuputStream。它实现了OutputStream的抽象方法write,把数据写入到OutputBuffer类型的字段中存着。而这个OutputBuffer对象来自于coyote/Response。其实这个OutputBuffer也只是一个接口,具体实现一直向下翻是StreamOutputBuffer。数据大小没有限制,是用链表存储的,每个链表节点存储8196字节。

    什么时候把响应数据报返回给客户端?

    其实就是查看,它是何时调用OutputBuffer的flush方法的。我逐层查看,最终定位到了connector/Response的finishResponse()方法。这个方法,会先发送响应行和响应头。然后再发送响应body。Tomcat的源码我看的不多,这里找到一张不错的时序图,描述的是一个HTTP请求的处理过程。如下,我们把重点放在servlet的service方法调用,和Response的fininshResponse方法调用上。可以得到,在service方法返回后,执行的就是finishResponse操作。也就是说,当servlet程序处理完这个请求后,tomcat就会把响应结果发回客户端

    注意:servlet的程序不参与底层数据的收发,或者说不控制

    servlet的service方法调用在图中哪里?

    包含在ApplicationFilterChain的internalDoFilter方法中。

    servlet程序处理请求指的是什么?

    根本上servlet程序做的工作就是,根据Request的信息,填充Response信息而已。

    servlet程序与Spring MVC是什么关系?

    Spring MVC底层还是Serlvet,它是把所有请求都用一个servlet处理,这个servlet叫做DispatcherServlet,而它又把请求分发给对应的@RequestMapping标注的方法进行处理。整体上来说就是完成一个service方法的调用。

    那MVC的返回页面,返回REST数据是怎么回事?

    返回页面就是把页面数据写入到响应Body中;@ResponseBody注解,实际上就是把@RequestMapping标注的方法的返回值转为JSON字符串写入到响应Body中。这里的响应Body指的就是前文中的OutputBuffer.

    Tomcat与Servlet程序的职责

    《How Tomcat works》中讲到,Servlet容器(Tomcat就是一种Servlet容器)的任务有概括地讲有三个

    1.创建一个Request对象,并填充相关信息(parameters、headers、cookie、uri等)

    2.创建一个Response对象

    3.调用与此请求关联的Servlet的service方法,把Request和Response传给它。

    这里我用自己的话讲一下:当浏览器向服务端发来一个请求时,服务端会将请求数据报的内容解析出来,创建一个填充有请求信息的Request对象,同时创建一个"空的"Response对象,然后把这两个对象传给servlet的service方法,让它来完成Response对象的填充,最后把Response数据发送给客户端。

    为什么要传Request对象?

    你不传Request对象,Servlet程序就不知道该填充什么。换句话说,它不知道你到底想要什么资源。

    Tomcat是如何找到请求关联的Servlet的?

    我们知道,Tomcat在开发的时候不可能知道你会往它里面部署什么项目,servlet程序叫什么。所以它不可能硬编码来调用service方法,它所使用的就是反射机制。

    想想在使用spring boot框架开发之前,我们是怎么部署项目的?就是把项目打包,然后放到Tomcat的webapp目录下。跑起来后,项目对应的URL就是localhost:8080/projectName/xxx这样是吧。而且,在项目中,不管是注解式的,还是web.xml式,都会配置Servlet程序的映射。把URL映射到某个Servlet类文件。

    当请求来临时,先根据projectName找到对应项目,再根据后续的URL映射到对应的Servlet类名。之后Tomcat就会利用反射机制加载Servlet类文件,获取实例,然后再调用service方法。

    coyote/Response、connector/Response、connector/ResponseFacade之间的关系?

    coyote/Response主要就是跟底层的数据传递挂钩的,而connector/Response是coyote/Response的上层包装,它实现了HttpServletResponse接口。但是如果将它直接传给service方法,则害怕用户直接将HttpServletResponse强转为connector/Response,直接调用底层的一些方法。所以引入了一个使用"Facade模式",将connector/Response除了HttpServletResponse接口定义的public方法都屏蔽掉。也就是说,传递给service的实际上是connector/ResponseFacade对象,就算强转为实际类型,也只能看到HttpServletResponse接口定义的方法。

    总结

    以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

    上一篇:Tomcat如何监控并删除超时Session详解
    下一篇:如何使用宝塔安装ionCube扩展
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    tomcat何时写回响应数据报的详析 tomcat,何时,写回,响应,数据,