Tomcat源码分析之:ServletOutputStream的实现

本文探讨了Tomcat中ServletOutputStream的实现,分析了数据在发送过程中的层次流动,从ServletOutputStream到OutputBuffer,再到InternalNioOutputBuffer,最终通过niochannel将数据发送出去。文章通过代码跟踪,详细解释了数据如何在不同缓冲区间移动,并讨论了非阻塞发送数据的支持情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

貌似很久都没有写博客了,tomcat8的代码已经看了很多,主体部分的代码也都看得差不多了,发现在tomcat8中已经完全支持非阻塞的方式接收以及发送数据了。。。。但是比较遗憾的是,以前遗留下来的太多的老代码都不支持这种新的方式来发送数据。。。木有办法。。。

这里来看看Tomcat中是如何实现ServletOutputStream的吧。。。。

在具体的来看它之前,这里先来一张图来描述一下Tomcat的数据发送时候的流动。。。



这张图形已经比较好的展现成了Tomcat中对IO这一块封装的层次关系吧,首先是最上层的

ServletOutputStream对象,它是用户代码可以接触到的对象,它自带了自己的OutputBuffer,这里写数据其实是通过这个这个buffer完成的,数据是写到这个OutputBuffer里面

接下来的一层就是Tomcat内部的Response类型了,每一个ServletResponse对象都对应着一个唯一的Tomcat内部的response类型,当然了,他也有自己的buffer,InternalNioOutputBuffer类型的对象,这里上层ServletOutputStream写数据将会流动到这里。。。

最下层就是与channel关联的部分了,它也有自己的buffer,这里一般就是java类库中的niobuffer,上层的数据将会流动到这里。。。

最后才是将数据通过channel发送出去。。。

嗯,虽然好像层次稍微多了些,而且刚刚开始看代码就觉得稍微有点繁琐。。不过当将这个层次关系理清楚了之后还是蛮简单的。。。

好啦,接下来来看代码了。。。

这里就通过一次write来跟踪整个代码的执行轨迹吧,首先来看看CoyoteOutputStream类型的write方法:

    //发送一个byte数组的一部分数据
    public void write(byte[] b, int off, int len) throws IOException {
        boolean nonBlocking = checkNonBlockingWrite();  //判断是否支持非阻塞的发送数据,这里判断的标准其实是用户代码是否加入了WriteListener
        ob.write(b, off, len);  //将数据写到outputbuffer里面
        if (nonBlocking) {
            checkRegisterForWrite();  //如果是非阻塞的发送数据的话,需要确保channel有注册写事件
        }
    }

这里首先要判断是否支持非阻塞的发送数据,这里就不细讲这部分的类容了,,,来看看这里的outputbuffer的write行为吧:

//写入一个字节数组的一部分
    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;
        }
        //这里其实是写到buffer里,如果数据过大,也有可能调用realWriteBytes方法真正的调用底层写数据
        bb.append(b, off, len);
        bytesWritten += len;

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

    }

这里其实就是将数据直接放到当年的bytechunk就好了。。。但是这里如果数据比较多的话,会将数据直接写到下一层,也就是tomcat内置的response。。。来看看bytechunk的append方法吧:

    //加入一个字节数组的一部分数据
    public void append( byte src[], int off, int len )
    
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值