首页 > 编程知识 正文

candleholder什么意思,request获取请求参数的方法

时间:2023-05-06 13:53:02 阅读:146929 作者:116

在Web开发中,通常需要在服务层或工具类中检索http servlet对象。 一种方法是将HttpServletRequest作为方法的参数从控制器层拖放并传递,这有点辛苦,也不优雅。 另一个是RequestContextHolder,直接在需要的地方取HttpServletRequest即可。 使用代码如下。

htpservletrequestrequest=((servletrequestattributes ) requestcontextholder.getrequest attributes ).getrequest () ) 要理解上述为什么可以这样使用,需要理解两个问题。

为什么RequestContextHolder可以获取当前http servlet

HttpServletRequest是什么时候设置为RequestContextHolder的

关于第一个问题,熟悉趋势科技的人应该很容易看出这是趋势科技的应用。 这一类的原理在之前的博客(ThreadLocal原理)中进行了阐述,其实和之前的博客文末所述的UserContextHolder很相似。

第二个问题应该是spring-mvc的问题,它在运行spring-mvc时设置

分析源代码

首先,让我们看看RequestContextHolder的源代码。 源代码如下:

publicabstractclassrequestcontextholder { privatestaticfinalthreadlocalrequestattributestributestattributesholder=NND cfinalthreadlocalrequestattributesinheritablerequestattributesholder=newnamedinheritablethreadlocalrequestattributer=newnatributer estatattri publicstaticvoidresetrequestattributes (({ requestattributesholder.remove ); inheritablerequestattributesholder.remove (; } publicstaticvoidsetrequestattributes (requestattributes ) setrequestattributes (attributes,false ); //RequestAttributes对象包含在ThreadLocal中,而HttpServletRequest、HttpServletResponse等封装在RequestAttributes对象中。 在本例中,无论是不是封装在requestattributes对象中,都必须检索requestattributes对象,然后必须从requestattributes对象检索所需的http servlet rerebutes对象publicstaticvoidsetrequestattributes,booleaninhhutes (else ) if(inheritable ) inheritablerequestattributesholder.set ) requestAttributesHolder.remove (; } else { requestattributesholder.set (attributes ); inheritablerequestattributesholder.remove (; } } publicstaticrequestattributesgetrequestattributes ({ requestattributesattributes=requestattributesholder.get ) } if ()

butes = inheritableRequestAttributesHolder.get(); } return attributes; }}

那么在spring-mvc中是怎么实现的呢,我们来简单分析的,想了解具体机制的可以去看看spring-mvc的源码。
我们看下FrameworkServlet这个类,也就是DispatcherServlet的父类,里面有个processRequest方法,根据方法名称我们也可以大概了解到这个是方法用于处理请求的。

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); //将RequestAttributes设置到RequestContextHolder 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 { //重置RequestContextHolder之前设置RequestAttributes 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); } } 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); } }

简单看下源码,我们可以知道HttpServletRequest是在执行doService方法之前,也就是具体的业务逻辑前进行设置的,然后在执行完业务逻辑或者抛出异常时重置RequestContextHolder移除当前的HttpServletRequest。

【多线程】ThreadLocal原理
使用
在每个线程的内部有个数据结构为Map的threadLocals变量,以<ThreadLocal,Value>的形式保存着线程变量和其对应的值。
当使用set()方法时:

1.获取到当前线程的threadLocals,类型为Map
2.将这值放到这个Map结构的变量中,key为ThreadLocal对象,value为所有存放的值

当使用get()方法时:

1.获取到当前线程的threadLocals,类型为Map。
2.以ThreadLocal对象为Map的key获取到它的value值。

因为ThreadLocal对象作为Map的key,所以一个ThreadLocal对象只能存放一个值,当存放多个时,会将新值覆盖旧值。

数据结构:

public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//当前线程为入参,获取当前线程的threadLocals变量 if (map != null) //入参为this,也就是说key为ThreadLocal对象 map.set(this, value); else createMap(t, value); } public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//当前线程为入参,获取当前线程的threadLocals if (map != null) { //入参为this,也就是说key为ThreadLocal ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } ThreadLocalMap getMap(Thread t) { return t.threadLocals;//threadLocals为线程的变量 } private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e);//避免内存泄漏,下文有提。 }

https://www.jianshu.com/p/6bf1adb775e0

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。