概述
如果我们将request
传递到异步线程中使用,可能获取不到参数,并且会导致后续的请求,使用到这个线程也会出问题。
原因就是request
对象会被重复使用。
源码分析
1、获取参数
先看一个非常重要的方法,getParameter
方法调用第一次,会进行参数的解析,之后就不再解析。
package org.apache.catalina.connector;public class Request implements HttpServletRequest {/*** 请求参数解析标志(默认为false)*/protected boolean parametersParsed = false;@Overridepublic String getParameter(String name) {if (!parametersParsed) { //判断是否已经解析参数,如果没解析,则进行解析。parseParameters();}return coyoteRequest.getParameters().getParameter(name);}
}
2、解析参数
真正解析参数的是 parameters.handleQueryParameters();
这个方法。
/*** 解析请求参数*/protected void parseParameters() {parametersParsed = true;Parameters parameters = coyoteRequest.getParameters();boolean success = false;try {......parameters.handleQueryParameters(); //真正解析参数的方法......success = true;} finally {if (!success) {parameters.setParseFailedReason(FailReason.UNKNOWN);}}}
3、将查询字符串处理为参数
/*** 将查询字符串处理为参数*/public void handleQueryParameters() {if (didQueryParameters) { //判断是否已经处理过了return;}didQueryParameters = true;......processParameters(decodedQuery, queryStringCharset);}
4、添加参数到 paramHashValues
程序执行到这里会将参数加入到 paramHashValues
这个map
中,获取参数时,就是直接从这个map
里获取的。
private final Map<String,ArrayList<String>> paramHashValues =new LinkedHashMap<>();public void addParameter( String key, String value )throws IllegalStateException {if( key==null ) {return;}parameterCount ++;if (limit > -1 && parameterCount > limit) {// Processing this parameter will push us over the limit. ISE is// what Request.parseParts() uses for requests that are too bigsetParseFailedReason(FailReason.TOO_MANY_PARAMETERS);throw new IllegalStateException(sm.getString("parameters.maxCountFail", Integer.valueOf(limit)));}ArrayList<String> values = paramHashValues.get(key);if (values == null) {values = new ArrayList<>(1);paramHashValues.put(key, values);}values.add(value);}
5、释放request
最终请求的代码会走到这个地方,request的参数会在这里被清除,然后准备给下个请求进行复用。
方法叫做 recycle,表明是循环再利用,在这里面会把存放参数的 Map 清空,把 didQueryParameters 再次设置为了 false。
public void recycle() {parameterCount = 0;paramHashValues.clear();didQueryParameters = false;charset = DEFAULT_BODY_CHARSET;decodedQuery.recycle();parseFailedReason = null;}
种种迹象表明 request 在 tomcat 里面是循环使用的。
参考:
https://blog.csdn.net/JavaMonsterr/article/details/126033884