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接口定义的方法。

总结

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

(0)

相关推荐

  • 深入分析Tomcat无响应问题及解决方法

    问题描述 生产环境下有几台tomcat,但突然某个时候发现所有的请求都不能响应了,由于我们的web server使用的是nginx,会将请求反向到tomcat上,所以起初怀疑是nginx就没有收到请求,但查看日志后发现,nginx中大量出现499的返回,这说明问题还是出在tomcat上. 问题排查 首先我想到的是不是CPU跑满了,虽说CPU没有报警但还是本能的top命令看下系统负载,发现系统只有0.x的负载,cpu,内存消耗都是正常的. 由于CPU没有出现异常,所以应该不是GC出现了问题,但还是

  • 在Tomcat服务器下使用连接池连接Oracle数据库

    下面介绍在Tomcat服务器下使用连接池来连接数据库的操作 一:修改web.xml文件: 复制代码 代码如下: <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:

  • 基于Tomcat 数据源的原理、配置、使用介绍

    1.数据源的作用及操作原理 在程序代码中使用数据源是可以提升操作性能的,这种性能的提升依靠于运行的原理. 传统JDBC操作步骤 1.加载数据库驱动程序,数据库驱动程序通过CLASSPATH配置: 2.通过DriverManager类取得数据库连接对象: 3.通过Connection实例化PreparedStatement对象,编写SQL命令操作数据库: 4.数据库属于资源操作,操作完成后进行数据库的关闭以释放资源.如图所示: 对于不同的用户只有操作不同,但是对于1.2.4三个步骤很明显是一个重复

  • Tomcat 5.5 数据库连接池配置

    Server.xml的修改我推荐使用Tomcat的Admin组件完成,完全图形化配置,相当容易.或者按下面的写法在< GlobalNamingResources>< /GlobalNamingResources>之间写如下配置(仅供参考,各位用的时候,请改成自己数据库的配置): 复制代码 代码如下: <Resource name="jdbc/mysql" type="javax.sql.DataSource" password=&quo

  • Tomcat数据源配置方法_JBuilder中

    其实tomcat中配置数据源有好几中方式,很灵活,所以也容易相互整窜,个人认为比较简单的方法就是在tomcat下的conf文件夹下的server.xml增加 复制代码 代码如下: <Context path="/test" docBase="test" debug= "99" reloadable="true" crossContext="true" verbosity="DEBUG&quo

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

    疑问的产生 这个疑问是我在写文件下载的时候产生的,我是用HttpServletResponse获取到Outputstream,然后利用OutputStream直接写数据的.当时我就想这个OutputStream是不是就是对应的Socket连接的OutputStream.即是不是的程序在用stream写的时候,数据也同时在发? Response的OutputStream把数据写到哪去? 于是我看了下HttpServletResponse的getOutputStream方法,看看它注释是怎么说的.

  • 实现一个VUE响应式属性装饰器详析

    目录 前言 不使用任何的响应Api 使用 reactive 实现 使用 ref 实现 使用装饰器实现 实现Reactive装饰器 实现Watch装饰器 总结 前言 使用面向对象的开发思想难免会用到类,既然有了类,那就应该有实例,然而我们使用类的时候可能需要实例中的某个属性是vue的响应属性,也可能里面的某个方法也可以被vue的watch监听.我就开始琢磨如何通过 Composition API 来实现这个类属性装饰器 不使用任何的响应Api // TestReactive.ts export c

  • 基于tomcat的连接数与线程池详解

    前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xml 中写到过:Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据:然后分配线程让Engine(也就是Servlet容器)来处理这个请求,并把产生的Request和Response对象传给Engine.当Engine处理完请求后,也会通过Conn

  • SpringBoot之自定义Filter获取请求参数与响应结果案例详解

    一个系统上线,肯定会或多或少的存在异常情况.为了更快更好的排雷,记录请求参数和响应结果是非常必要的.所以,Nginx 和 Tomcat 之类的 web 服务器,都提供了访问日志,可以帮助我们记录一些请求信息. 本文是在我们的应用中,定义一个Filter来实现记录请求参数和响应结果的功能. 有一定经验的都知道,如果我们在Filter中读取了HttpServletRequest或者HttpServletResponse的流,就没有办法再次读取了,这样就会造成请求异常.所以,我们需要借助 Spring

  • GitHub上77.9K的Axios项目有哪些值得借鉴的地方详析

    目录 前言 一.Axios 简介 二.HTTP 拦截器的设计与实现 2.1 拦截器简介 2.2 任务注册 2.3 任务编排 2.4 任务调度 三.HTTP 适配器的设计与实现 3.1 默认 HTTP 适配器 3.2 自定义适配器 四.CSRF 防御 4.1 CSRF 简介 4.2 CSRF 防御措施 4.2.1 检查 Referer 字段 4.2.2 同步表单 CSRF 校验 4.2.3 双重 Cookie 防御 4.3 Axios CSRF 防御 五.参考资源 总结 前言 Axios 是一个基

  • Tomcat用户管理的优化配置详解

    目录 tomcat用户管理配置 tomcat优化 一.tomcat中的三种运行模式之运行模式的优化 二.tomcat执行器(线程池)的优化 三.tomcat优化之禁用AJP连接器实现动静分离 四.tomcat中JVM参数优化 tomcat用户管理配置 在tomcat-users.xml中添加用户: <role rolename="manager"/> <role rolename="manager-gui"/> <role rolena

  • Java关键字volatile详析

    目录 一.可见性 二.关于指令重排 volatile关键字关于先说它的两个作用: 保证变量在内存中对线程的可见性 禁用指令重排 每个字都认识,凑在一起就麻了 这两个作用通常很不容易被我们Java开发人员正确.完整地理解,以至于许多同学不能正确地使用volatile 一.可见性 码: public class VolatileTest {     private static volatile int count = 0;     private static void increase() {

  • Vue组件间的通信方式详析

    目录 前言 组件之间通信的场景 父子组件之间的通信 父组件通过 prop 向子组件传递数据 子组件通过自定义事件向父组件传递数据 兄弟组件之间的通信 状态提升 隔代组件之间的通信 attrs/attrs/listeners provide/inject 基于 $parent/$children 实现的 dispatch 和 broadcast 前言 在Vue组件库开发过程中,Vue组件之间的通信一直是一个重要的话题,虽然官方推出的 Vuex 状态管理方案可以很好的解决组件之间的通信问题,但是在组

  • Linux 单个tomcat多实例部署shell脚本详解

    Linux 单个tomcat多实例部署shell脚本详解 步骤: 1. 下载tomcat,解压安装 2.将tomcat下的webapps,conf,temp等目录分别拷至根目录www下A,B,C目录下 3.新建如下脚本restart_tomcat.sh 4.使用restart_tomcat.sh A/B/C #!/bin/sh if [ -z $1 ] then echo "\033[31;1mplease input the app which you need restart...\033[

  • 基于Tomcat安全配置与性能优化详解

    Tomcat 是 Apache软件基金会下的一个免费.开源的WEB应用服务器,它可以运行在 Linux 和 Windows 等多个平台上,由于其性能稳定.扩展性好.免费等特点深受广大用户喜爱.目前,很多互联网应用和企业应用都部署在 Tomcat 服务器上,比如我们公司,哈. 之前我们 tomcat 都采用的是默认的配置,因此在安全方面还是有所隐患的.上周对测试环境的所有服务器的tomcat都做了安全优化,其间也粗略做了一些性能优化,这里就简单记录分享下! 一.版本安全 升级当前的tomcat版本

随机推荐