惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
博客园 - 聂微东
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
V
Visual Studio Blog
博客园 - 司徒正美
爱范儿
爱范儿
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
博客园 - 【当耐特】
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
人人都是产品经理
人人都是产品经理
V
V2EX

博客园 - wastonl

maven选择settings.xml策略 RocketMQ消费机制整理 RocketMQ重平衡机制 @JacksonXmlElementWrapper使用限制 JSR303和SpringBoot参数校验机制 同一Java进程生产者和消费者与MqClientInstance对应关系 RocketMQ自动创建主题机制 SpringMVC异步请求 tomcat异步请求机制 Spring异步任务和定时任务 Spring ResolvableType说明 Jvm内存以及垃圾回收相关知识 RocketMQ如何保证消息可靠性 RocketMQ整体架构 mybatis-plus易忘点笔记 SpringMVC使用Resource实现二进制传输(下载) Spring事件异步执行设计与实现 Spring Bean销毁机制 Spring Lifecycle组件 Zipkin Brave使用 Spring Boot日志系统简要介绍 spring cloud sleuth基本使用 Spring懒加载与@Lazy注解 https碎碎念 ES脚本使用 SpringMVC静态资源处理 Maven插件运行方式 如何使用Maven将项目中的依赖打进jar包 时区以及时区对于Java时间类格式化的影响 SpringMVC处理请求头、响应头、编码行为
tomcat自动刷新响应输出流缓冲区
wastonl · 2025-08-04 · via 博客园 - wastonl

小知识点

如下代码没有主动调用flush或者close方法时,浏览器也能拿到响应数据,是因为tomcat内部的Servlet中的service方法执行完毕后,会自动调用close方法刷新缓冲区的数据。

@GetMapping("/hello")
public void hello(HttpServletResponse response) throws IOException {
    // 只是写到响应流内部的缓冲区(ByteBuffer)中,当写入的内容超过缓冲区大小时会自动刷新数据
    response.getOutputStream().write("hello world".getBytes(StandardCharsets.UTF_8));
}

tomcat中的响应输出流实现为CoyoteOutputStream

CoyoteOutputStream.java

@Override
public void write(byte[] b, int off, int len) throws IOException {
    boolean nonBlocking = checkNonBlockingWrite();
    ob.write(b, off, len);
    if (nonBlocking) {
        checkRegisterForWrite();
    }
}

@Override
public void flush() throws IOException {
    boolean nonBlocking = checkNonBlockingWrite();
    ob.flush();
    if (nonBlocking) {
        checkRegisterForWrite();
    }
}

@Override
public void close() throws IOException {
    ob.close();
}


OutputBuffer.java

public void write(byte b[], int off, int len) throws IOException {
    if (suspended) {
        return;
    }
    writeBytes(b, off, len);
}

private void writeBytes(byte b[], int off, int len) throws IOException {
    if (closed) {
        return;
    }
    // 追加到内部的ByteBuffer中,没有剩余空间时会写入到底层的socket中,同时清空ByteBuffer
    append(b, off, len);
    bytesWritten += len;

    // if called from within flush(), then immediately flush
    // remaining bytes
    if (doFlush) {
        flushByteBuffer();
    }
}

接下来是tomcat内部执行顺序

Http11Processor.service -> CoyoteAdapter.service -> org.apache.coyote.Response.finishResponse -> OutputBuffer.close

其中CoyoteAdapter.service会调用Servlet的service方法执行响应逻辑

CoyoteAdapter.service

// 这一行会触发Servlet的执行
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);