看源码的时候发现可以在
service
获取request
和response
,正常来说在service
层是没有request
的,然而直接从controlller
传过来的话解决方法太粗暴,后来发现了SpringMVC提供的RequestContextHolder
来研究一下,并借此对SpringMVC的结构深入了解一下
1.RequestContextHolder的使用
RequestContextHolder
顾名思义,持有上下文的Request
容器.使用是很简单的,具体使用如下:
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//RequestContextHolder.getRequestAttributes();
//从session里面获取对应的值
String str = (String) requestAttributes.getAttribute("name",RequestAttributes.SCOPE_SESSION);
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)requestAttributes).getResponse();
看到这一般都会想到几个问题:
request和response怎么和当前请求挂钩?
request和response等是什么时候设置进去的?
2.解决疑问
2.1 request和response怎么和当前请求挂钩?
首先分析
RequestContextHolder
这个类,里面有两个ThreadLocal
保存当前线程下的request
//得到存储进去的request
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<RequestAttributes>("Request attributes");
//可被子线程继承的request
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
new NamedInheritableThreadLocal<RequestAttributes>("Request context");
再看
getRequestAttributes()
方法,相当于直接获取ThreadLocal里面的值,这样就保证了每一次获取到的Request是该请求的request.
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = requestAttributesHolder.get();
if (attributes == null) {
attributes = inheritableRequestAttributesHolder.get();
}
return attributes;
}
2.2request和response等是什么时候设置进去的?
找这个的话需要对springMVC结构的
DispatcherServlet
的结构有一定了解才能准确的定位该去哪里找相关代码.
要分析的的就是三个类,简单看下源码
-
HttpServletBean
进行初始化工作 -
FrameworkServlet
初始化WebApplicationContext
,并提供service方法预处理请 -
DispatcherServlet
具体分发处理.
那么就可以在FrameworkServlet
查看到该类重写了service(),doGet(),doPost()...等方法,这些实现里面都有一个预处理方法processRequest(request, response);
,所以定位到了我们要找的位置
查看processRequest(request, response);
的实现,具体可以分为三步:
- 获取上一个请求的参数
- 重新建立新的参数
- 设置到XXContextHolder
- 父类的service()处理请求
- 恢复request
- 发布事