异步线程使用Request存在问题

概述

如果我们将request传递到异步线程中使用,可能获取不到参数,并且会导致后续的请求,使用到这个线程也会出问题。
原因就是request对象会被重复使用。

源码分析

1、获取参数

先看一个非常重要的方法,getParameter 方法调用第一次,会进行参数的解析,之后就不再解析。

package org.apache.catalina.connector;

public class Request implements HttpServletRequest {
    /**
     * 请求参数解析标志(默认为false)
     */
    protected boolean parametersParsed = false;

    @Override
    public 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 big
            setParseFailedReason(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.youkuaiyun.com/JavaMonsterr/article/details/126033884

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值