Jetty9源码剖析 - Connection组件 - HttpInput

转载自ph0ly:http://www.ph0ly.com

一、概念

HttpInput是Jetty实现ServletInputStream的类,主要用于应用层对Request的输入流操作,主要是请求体的操作

二、继承体系

继承体系

继承自ServletInputStream,实现了Runnable,很简单

三、源码剖析

1. 创建

创建

前面在HttpChannel章节讲到过,HttpInput是HttpChannel创建Request对象的时候创建,会同时附带一个HttpChannelState状态对象,这个主要是控制异步流程

2. 流读取

其实对于HttpInput来说,最核心的就是流的读取,我们重点就看下这个方法的实现

read

对于一个流来说,这个read方法就是比较核心的了,我们使用三方工具例如guava或者其他流读取类,通常都会调到这个方法,我们可以看到这里第一步对_inputQ加锁,其实这个_inputQ就是一个缓冲队列,Jetty这里用了生产者消费者模式,如果这个时候_inputQ没数据,就让HttpConnection.fillAndParseForContent,要求EndPoint从Channel读取数据,读取完了同时会要求解析,这个时候的HttpParser其实的状态其实是CONTENT(如果读者不理解,可以回到HttpParser章节重温一下),因此HttpParser调用HttpChannelOverHttp的content接口,如下图

HttpChannel.content

这是HttpChannelOverHttp的content方法,会让HttpConnection生成一个新的HttpConnection下面的Content,并调用onContent将这个Content放到HttpInput,如下图

HttpConnection.onContent

这里就直接从HttpChannelOverHttp拿到Request对象,再拿HttpInput,直接调addContent方法,接下来再来看HttpInput.addContent如何实现

addContent

可以看到其实就是往_inputQ放这个Content,而这个Content其实就包装了这些数据的ByteBuffer,这里利用队列,保证HttpParser能不阻塞解析。当整个流读完了,HttpParser会触发HttpChannelOverHttp的onRequestComplete方法,该方法会调用HttpInput.eof方法,如下图

eof

HttpInput的eof方法会调用addContent添加一个EOF_CONTENT,表示没有数据可以读了

再回到上面HttpInput.read方法,它调用了nextContent,要求从_inputQ读取数据,如下图

nextContent

pollContent

如果没拿到,就调用produceContent

produceContent

其实就是调到了HttpConnection.fillAndParseForContent,如下图

HttpConnection.fillAndParseForContent

上面也简单提了下,这里会要求EndPoint去读数据,每读取一块缓冲后解析一次,直到整个HttpParser已经完成Content的解析,HttpParser会把解析后的Content放到_inputQ,同时最后放一个EOF_CONTENT,表示没数据了

之后一直去调pollContent,拿到每一个Content

read-2

拿到Content后,会直接调get方法,把当前Content的数据拷贝到外面传入的缓冲b里面,然后consumeNonContent,如下图,如果拿到的item是null,这里会调用HttpInput的blockForContent,阻塞拿,后面拿到数据会通知_inputQ的线程继续执行

consumeNoContent

这个方法其实就是从队列移除掉刚才处理的Content,因为前面我们已经将缓冲拷贝出来了。最后再尝试获取新的Content,如果发现是 EofContent,这里就会结束读取

3. 回收

recycle

前面提到Request、Response、HttpInput、HttpOutput都是同一连接复用的,复用就需要回收,重置状态,recycle就是HttpInput的重置方法,这里会把_inputQ的Content全部通知失败,然后其他的值恢复最开始的状态

四、总结

HttpInput作为ServletInputStream的实现,主要完成了对请求体的处理,Jetty借助于_inputQ队列来隔离框架解析和应用层业务,是比较合理的做法,可以看出HttpInput最核心就是这个_inputQ的设计了。另外HttpInput还有一些其他的逻辑,一些异步的处理,例如Servlet3.1提供了ReadListener这样的监听器,这篇文章并没有提到,其实属于Servlet3异步的处理,后续有专题文章来分析,这里为了便于大家理解,只讲了同步,毕竟异步了就会出现状态机这样复杂的操作,很容易搞晕的。这篇文章就到这里,希望读者对Jetty对输入流的实现有一定的理解,接下来的文章我会分析HttpOutput以及HttpGenerator的实现,欢迎大家持续关注~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值