关于Spring MVC在控制器层中注入请求的坑详解

  

  

记一次为了节省代码没有在方法体中声明HttpServletRequest,而用自动装配直接注入所钻的坑
  

  

结论:给心急的人。直接在控制器的成员变量上使用@Autowire声明HttpServletRequest,这是线程安全的!

        @ controller   公开课TestController {   @Autowire   HttpServletRequest请求;   @RequestMapping (“/?   公共空白测试(){   request.getAttribute (“uid”);   }   }      

结论如上。

  

  

是这样的,由于项目中我在请求的头部加入身份验证信息,而我在拦截器截获信息并且验证通过后,会将当前用户的身份加到请求的属性中,方便在控制器层拿出来复用。

  

疑问:为什么不直接在控制器上使用@RequestHeader取出来呢?因为标题里面是加密后的数据,且要经过一些复杂的身份验证判断,所以直接将这一步直接丢在了拦截器执行。

  

所以当解密后,我将用户信息(如uid)用<代码> request.setAttribute() 设入请求中在控制器中提取。

  

而如果需要使用请求,一般需要在方法上声明,如:

        公共结果保存(HttpServletRequest请求){//dosomething ();   }      

那么我每个方法都要用到uid的岂不是每个方法都要声明一个请求参数,为了节省着个冗余步骤。我写了一个基类。

        公开课CommonController {   @Autowire   HttpServletReqeust请求;   公共字符串getUid () {   返回(String) request.getAttribute (“uid”);   }   }      

后来我就担心,因为控制器是单例的,这么写会不会导致后面的reqeust覆盖前面的请求,在并发条件下有线程安全问题。于是我就到segmentFault上提问,大部分网友说到,确实有线程问题! segmentFault问题地址# # #验证过程因为网友大部分的观点是只能在方法上声明,我自然不想就此放弃多写那么多代码,于是开始我的验证过程。热心的程序员们给我提供了好几种解决方案,我既然花力气证明了,就把结果放在这里,分享给大家。

  

  

第一个方法就是在控制器的方法中显示声明HttpServletReqeust,代码如下:

        @RequestMapping(“/测试”)   @RestController   公开课ct {   日志记录器=LoggerFactory.getLogger (getClass ());   @RequestMapping ("/iiii”)   公共字符串测试(HttpServletRequest请求){   logger.info (request.hashCode () + " ");   返回null;   }   }      

在浏览器狂按F5

  

<强>输出

  

关于Spring MVC在控制器层中注入请求的坑详解

  

当时我是懵逼的,* *说好的线程安全呢! * *这特么不是同一个请求吗!特么的在逗我!为此我还找了很久请求是不是重写了hashcode () !

  

啊,事实是这样的,因为我用浏览器狂按F5,再怎么按他也是模拟不了并发的。那么就相当于,服务器一直在用同一个线程处理我的请求就足够了,至于这个请求的hashcode,按照jdk的说法是根据obj在jvm的虚拟地址计算的,后面的事情是我猜的,如果有知道真正真想的还望告知!

  

<强>猜测

  

服务器中每个线程所申请的请求的内存空间在这个服务器启动的时候就是固定的,那么我每次请求,他都会在他所申请到的内存空间(可能是类似数组这样的结构)中新建一个请求,(类似于数组的起点总是同一个内存地址),那么我发起一个请求,他就会在起始位置新建一个请求传递给Servlet并开始处理,处理结束后就会销毁,那么他下一个请求所新建的请求,因为之前的请求销毁了,所以又从起始地址开始创建,这样一切就解释得通了!

  

<强>猜测完毕

  

<强>验证猜想:

  

我不让他有销毁的时间不就可以了吗测试代码

        @RequestMapping(“/测试”)   @RestController   公开课ct {   日志记录器=LoggerFactory.getLogger (getClass ());   @RequestMapping("/呜”)   公共字符串外种皮(HttpServletRequest请求){抛出异常   thread . sleep (3000);   logger.info (request.hashCode () + " ");   logger.info (reqeust.getHeader (“uid”);   返回null;   }   @RequestMapping ("/iiii”)   公共字符串测试(HttpServletRequest请求){   logger.info (request.hashCode () + " ");   logger.info (reqeust.getHeader (“uid”);   返回null;   }   }

关于Spring MVC在控制器层中注入请求的坑详解