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

推荐订阅源

G
Google Developers Blog
D
Docker
Stack Overflow Blog
Stack Overflow Blog
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
H
Help Net Security
T
Tailwind CSS Blog
Engineering at Meta
Engineering at Meta
L
LangChain Blog
MongoDB | Blog
MongoDB | Blog
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
S
SegmentFault 最新的问题
博客园 - 司徒正美
C
Check Point Blog
B
Blog
Y
Y Combinator Blog
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
F
Fortinet All Blogs
美团技术团队
D
DataBreaches.Net

博客园 - 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);