在 Service 层或者某一个工具类中获取到 HttpServletRequest 对象的场景还是比较常见的。一种方法是将 HttpServletRequest 对象作为方法的入参从 Controller 层一直往下传递。不过这样比较费劲,不够优雅。还有一种就是利用 RequestContextHolder,在需要 HttpServletRequest 的时候,用如下方式获取
1 | package io.renren.common.utils; |
要理解为什么可以这么使用,需要明白两个问题:
RequestContextHolder为什么能获取到当前的HttpServletRequest?HttpServletRequest是在什么时候设置到RequestContextHolder的?
对于第 1 个问题,熟悉 ThreadLocal 的人应该很容易看出来这个是利用 ThreadLocal 获取到的。第 2 哥问题应该是属于 SpringMVC 的问题
源码分析
首先看一下 RequestContextHolder 的源码
1 | public abstract class RequestContextHolder { |
setRequestAttributes() 方法的作用就是:将 RequestAttributes 对象放入到 ThreadLocal 中。而 HttpServletRequest和 HttpServletResponse 等则封装在 RequestAttributes 对象中,在此处就不对 RequestAttributes 这个类展开。反正我们需要知道的就是要获取 RequestAttributes 对象,然后再从 RequestAttributes 对象中获取到我们所需要的 HttpServletRequest 即可
那么在 SpringMVC 中是怎么实现的呢,看看 DispatcherServlet 的的父类 FrameworkServlet 的源码。
1 | /** |
简单看下源码,我们可以知道 HttpServletRequest 是在执行 doService 方法之前,也就是具体的业务逻辑前进行设置的,然后在执行完业务逻辑或者抛出异常时重置 RequestContextHolder 移除当前的 HttpServletRequest
写本文的目的主要是记录下这个 RequestContextHolder 的使用,以及希望以后能在业务代码中巧用该工具让自己的代码更加简洁优雅