SpringMVC学习记录(九(-RequestContextHolder分析
选项卡(以空格分隔):javaWEB
最近面临的问题是在服务中获取请求和响应。 服务层通常没有请求。 但是,如果是直接从控制ller那里传来的话,解决方法太粗暴了。 然后,我们发现并分析了SpringMVC提供的RequestContextHolder,并将其借用
1 .使用1.RequestContextHolder
RequestContextHolder顾名思义,是具有上下文的Request容器。 使用简单,具体使用以下:
//两种方法在没有使用JSF的项目中是分不开的
requestattributesrequestattributes=requestcontextholder.currentrequestattributes (;
//requestcontextholder.getrequest attributes (;
从会话中获取对应的值
String str=(String ) request attributes.getattribute (' name ',request attributes.scope _ session );
htpservletrequestrequest=((servletrequestattributes ) requestattributes ).getRequest );
httpservletresponseresponse=((servletrequestattributes ) requestattributes ).getResponse );
看到这个,一般会想到几个问题:
1 .请求和响应如何与当前请求联系起来?
2 .请求和响应等是什么时候设置的?
2 .解决疑问
2.1请求和响应如何与当前请求联系起来?
首先分析一个名为RequestContextHolder的类时,两个ThreadLocal存储当前线程上的请求。 关于ThreadLocal,请参考我的另一篇博文Java学习记录thread local的使用案例
//获得保存的请求
privatestaticfinalthreadlocalrequestattributesrequestattributesholder=
newnamedthreadlocalrequestattributes (请求属性);
//被子线程可继承request
私密性staticfinalthreadlocalrequestattributesinheritablerequestattributesholder=
newnamedinheritablethreadlocalrequestattributes ('请求上下文);
另外,如果观察getRequestAttributes ()方法,则相当于直接取得ThreadLocal中的值,由此确保每次取得时Request都是该请求的Request。
publicstaticrequestattributesgetrequestattributes (
requestattributesattributes=requestattributesholder.get (;
if (属性==null ) {
attributes=inheritablerequestattributesholder.get (;
}
返回属性;
}
2.2请求、响应等是什么时候设置的?
要查找它,必须了解springMVC结构的dispatcher servlet的结构,才能准确地找到应该在哪里查找相关代码。
IDEA显示以下继承关系:
左边是servlet的接口和实现类。
右侧是使SpringMVC具有Spring的几个环境变量和Spring容器。 同样的xxxAware接口为这个类提供了Spring识别,简单来说,如果想使用Spring的XXX,就可以实现XXXAware,Spring会发送所需的东西。
剩下的是三个班
简单看下源码1. HttpServletBean 进行初始化工作
2. FrameworkServlet 初始化 WebApplicationContext,并提供service方法预处理请求
3. DispatcherServlet 具体分发处理.
那么就可以在FrameworkServlet查看到该类重写了service(),doGet(),doPost()…等方法,这些实现里面都有一个预处理方法processRequest(request, response);,所以定位到了我们要找的位置
查看processRequest(request, response);的实现,具体可以分为三步:
1. 获取上一个请求的参数
2. 重新建立新的参数
3. 设置到XXContextHolder
4. 父类的service()处理请求
5. 恢复request
6. 发布事件
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//获取上一个请求保存的LocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//建立新的LocaleContext
LocaleContext localeContext = buildLocaleContext(request);
//获取上一个请求保存的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//建立新的RequestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//具体设置的方法
initContextHolders(request, localeContext, requestAttributes);
try {
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
//恢复
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
//发布事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
再看initContextHolders(request, localeContext, requestAttributes)方法,把新的RequestAttributes设置进LocalThread,实际上保存的类型为ServletRequestAttributes,这也是为什么在使用的时候可以把RequestAttributes强转为ServletRequestAttributes.
private void initContextHolders(
HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
if (localeContext != null) {
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
}
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
if (logger.isTraceEnabled()) {
logger.trace("Bound request context to thread: " + request);
}
}
因此RequestContextHolder里面最终保存的为ServletRequestAttributes,这个类相比RequestAttributes方法是多了很多.
项目示例可以参考:
SSM框架整合: https://github.com/nl101531/JavaWEB