在 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
的使用,以及希望以后能在业务代码中巧用该工具让自己的代码更加简洁优雅