0%

springboot奇怪问题【1】—— HttpServletRequest和@Async搭配使用

HttpServletRequest和@Async搭配使用问题

问题描述:希望将request中参数传递到service中处理,同时service是使用异步@Async,此时通过request.getParameterMap()获取参数列表只能在程序启动第一次才能获取到,第二次及之后获取为空,测试如果去掉@Async注解则每次都能获取到参数.

// Controller层
@GetMapping("/call")
public String callback(HttpServletRequest request) {
    // 这是一个异步方法
    service.call(request.getParameterMap());
    return "ok";
}
// Service层
@Async
public String call(Map<String, String[]>extras) {
    //todo 
    // 对extras做处理
    return "ok";
}

问题解决

// Controller层
@GetMapping("/call")
public String callback(HttpServletRequest request) {
    // 需要创建一个新的map,将request中参数导入,再传递到异步方法中
    Map<String, String[]> extras = new HashMap<>();
    extras.putAll(request.getParameterMap());
    service.call(extras);
    return "ok";
}

原因分析

  • request.getParameterMap()返回的是一个Map类型的值,该返回值记录着前端所提交请求中的请求参数和请求参数值的映射关系。这个返回值有个特别之处——只能读。不像普通的Map类型数据一样可以修改。这是因为服务器为了实现一定的安全规范,所作的限制。

  • 如果实在有必要在取得此值以后做修改的话,要新建一个map对象,将返回值复制到此新map对象中进行修改,用新的map对象代替使用之前的返回值。

  • 源码分析

// Collections.unmodifiableMap()方法使得集合为只读。
public Map getParameterMap() {
    Map result = new HashMap();
    if (!this.paramsSnapshot.isEmpty()) {
        result.putAll(this.paramsSnapshot);
    }
    result.putAll(super.getParameterMap());
    return Collections.unmodifiableMap(result);
}