Tomcat源码分析

接口偶发报错缺少必填参数,经过排查分析,发现报错缺少参数时,其实客户端是传了参数的。

经过分析发现,这种现象是把HttpServletRequest对象传到了异步线程中使用引起的。

Request对象是tomcat创建的,用于封装一次http请求相关的信息,当一次请求结束后,Request对象并不会被销毁,Request对象会被回收,tomcat只是把Request对象中的所有属性重置为初始状态,清空参数,然后放入队列,供其他请求使用。

tomcat源码分析

tomcat 包含三种 EndPoint:

org.apache.tomcat.util.net.NioEndpoint.java
org.apache.tomcat.util.net.JIoEndpoint.java
org.apache.tomcat.util.net.AprEndpoint.java

EndPoint 用于接受客户端 socket 请求(由内部类 Poller 完成),然后对 Socket 进行简单处理(由内部类 SocketProcessor 完成),接着转交给对应的 ProtocolProcessor 进行处理,封装成 request,通过各个Container 后 到达 servlet。

Processor回收栈

每次处理客户端请求,会先从Processor回收栈(recycleProcessors)中pop出一个processor对象,如果没取到,则会创建一个Processor。(Processor回收栈的默认大小是200,可通过max_connection参数调整)

 

首次创建processor

每创建一个Processor对象,会同时创建一个Request、Response对象,Processor对象和Request、Response是一一对应的。(所以Request对象是跟随Processor对象进行回收并循环复用的)

 

 

请求处理结束,释放processor资源

 

 

回收资源

 

 

 

request.getParameter()方法,会判断是否解析过参数,第一次调用该方法,会解析参数(byte转成String),然后放到paramHashValues中,后面通过getParameter获取参数会去paramHashValues中取。

 

当一次请求结束后,本次请求的Processor对象中的所有元素属性(包括request、response等)会重置,然后Processor对象会push进入processor回收栈,供下次请求使用。

如果把Request对象传入了异步线程,异步线程执行比较慢时,会出现Processor对象已经放入回收栈中,下一次请求拿到了这个Processor对象,并使用其中的Request对象,在通过Request对象取参数前,异步线程中通过Request.getParameter获取参数,此时,会把didQueryParameters置为true,

而此时新的请求中还没有执行到给Request对象赋值,此时就出现获取不到参数的现象。

本地模拟异步传递Request对象的场景进行debug验证

把Request对象传入异步线程,异步线程sleep10秒(确保同步请求处理结束),然后通过Request对象获取参数。

预期结果:等待10秒待异步线程获取Request中的参数后,再通过postman请求该接口,此时会报缺少参数异常。

由于本地调试每次只发1个请求,所以第一次访问接口新建Processor对象以及Request对象,后续请求都是使用的第一次请求创建的Processor。

出现缺少参数异常时,getParameter查询到的数据

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值