注意事項:
- 不要在請求方法裡另起一個子線程調用該方法;
- 在請求週期中,儘可能不要傳遞Request實例給多線程使用,因為子線程可能在Request生命週期結束銷燬後再使用Request時獲取不了參數,否則必須同步線程 讓其在生命週期結束前調用;
在Spring Boot中,如果我們要獲取當前Request實例,可以通過以下這個方法獲取。
<code>HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();/<code>
使用這種方法獲取的時候需要注意使用多線程會出現些狀況,例如一個請求過來後,請求達到Service方法,然後Service方法裡另起一個線程啟動,在該線程run方法裡面想要通過以上方法可能獲取不到Request實例。
且看RequestContextHolder內部分源碼:
<code> private static final ThreadLocal<requestattributes> requestAttributesHolder = new NamedThreadLocal<>("Request attributes"); private static final ThreadLocal<requestattributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal<>("Request context");..... /** * Bind the given RequestAttributes to the current thread. * @param attributes the RequestAttributes to expose, * or {@code null} to reset the thread-bound context * @param inheritable whether to expose the RequestAttributes as inheritable * for child threads (using an {@link InheritableThreadLocal}) */ public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) { if (attributes == null) { resetRequestAttributes(); } else { if (inheritable) { inheritableRequestAttributesHolder.set(attributes); requestAttributesHolder.remove(); } else { requestAttributesHolder.set(attributes); inheritableRequestAttributesHolder.remove(); } } } /** * Return the RequestAttributes currently bound to the thread. * @return the RequestAttributes currently bound to the thread, * or {@code null} if none bound */ @Nullable public static RequestAttributes getRequestAttributes() { RequestAttributes attributes = requestAttributesHolder.get(); if (attributes == null) { attributes = inheritableRequestAttributesHolder.get(); } return attributes; }/<requestattributes>/<requestattributes>/<code>
可看到之所以能通過靜態方法getRequestAttributes獲取Request實例,是因為ThreadLocal獲取。一個請求到達容器後,Spring會把該請求Request實例通過setRequestAttributes方法 把Request實例放入該請求線程內ThreadLocalMap中,然後就可以通過靜態方法取到。原理就是ThreadLocal,但ThreadLocal不能讓子線程繼承ThreadLocalMap信息,可以使用InherbritableThreadLocal實現子線程信息傳遞。 但Spring Boot 默認使用ThreadLocal把Request設置進請求線程中,這樣如果在請求方法裡面另起一個子線程然後再通過getRequestAttributes方法獲取,是獲取不到的。
所以要在能讓子線程獲取到,就可以使用InherbritableThreadLocal,看setRequestAttributes方法有這個布爾值可以設,至於在哪裡設就沒去深究。但個人認為最好不要修改該布爾值,默認就行,否則會有意向不到的可能閱讀更多 架構師的修煉之路 的文章
關鍵字: 請求 ThreadLocal getRequestAttributes