最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談SpringMVC HandlerInterceptor詭異問(wèn)題排查

 更新時(shí)間:2019年05月22日 14:39:19   作者:戒嗔  
這篇文章主要介紹了淺談SpringMVC HandlerInterceptor詭異問(wèn)題排查,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

發(fā)現(xiàn)問(wèn)題

最近在進(jìn)行壓測(cè)發(fā)現(xiàn),有一些接口時(shí)好時(shí)壞,通過(guò)sentry日志平臺(tái)及sky walking平臺(tái)跟蹤發(fā)現(xiàn),用戶張三獲取到的用戶上下文確是李四。

代碼走讀

用戶登錄下上文

/**
 * 用戶登錄下上文
 *
 * @author : jamesfu
 * @date : 22/5/2019
 * @time : 9:18 AM
 */
@Data
public class UserContext {
  private final static ThreadLocal<UserContext> threadLocal = new ThreadLocal<>();

  private Long id;

  private String loginName;

  public static UserContext get() {
    UserContext context = threadLocal.get();
    if (context == null) {
      // TODO(james.h.fu):根據(jù)請(qǐng)求上下文獲取token, 然后恢復(fù)用戶登錄下上文
      context = new UserContext() {{
        setId(1L);
        setLoginName("james.h.fu1");
      }};
      threadLocal.set(context);
    }

    return context;
  }

  public static void clear() {
    threadLocal.remove();
  }

  public static void set(UserContext context) {
    if (context != null) {
      threadLocal.set(context);
    }
  }
}

在攔截器中有調(diào)用UserContext.set恢復(fù)用戶登錄上下文,并在請(qǐng)求結(jié)束時(shí)調(diào)用UserContext.clear清理用戶登錄上下文。

攔截器注冊(cè)配置

/**
 * 攔截器注冊(cè)配置
 *
 * @author : jamesfu
 * @date : 22/5/2019
 * @time : 9:15 AM
 */
@Configuration
public class FilterConfig implements WebMvcConfigurer {
  @Autowired
  private JsonRpcInterceptor jsonRpcInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(jsonRpcInterceptor)
        .addPathPatterns("/json.rpc");
  }
}

 

 

通過(guò)debug可以發(fā)現(xiàn)UserContext中的ThreadLocal的清理工作沒(méi)有得到執(zhí)行。導(dǎo)致請(qǐng)求進(jìn)來(lái)時(shí),有可能ThreadLocal已存在了,就不會(huì)再根據(jù)請(qǐng)求上下文恢復(fù)了。

springmvc 源碼走讀

tomcat 在收到http請(qǐng)求后,最終會(huì)交由spring mvc的 DispatcherServlet 處理。 這里可以從doDispatch按圖索驥,順藤摸瓜地往下看起走。

源碼走讀:DispatcherServlet

/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception

請(qǐng)求會(huì)得到分發(fā),然后執(zhí)行各個(gè)已注冊(cè)Handler的preHandle-->postHandle-->afterCompletion。

源碼走讀:HandlerExecutionChain applyPreHandle

/**
	 * Apply preHandle methods of registered interceptors.
	 * @return {@code true} if the execution chain should proceed with the
	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
	 * that this interceptor has already dealt with the response itself.
	 */
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

當(dāng)執(zhí)行到preHandle返回false時(shí),它就會(huì)從上一個(gè)返回true的handler依次往前執(zhí)行afterCompletion,它自己的afterCompletion得不到執(zhí)行。

triggerAfterCompletion

/**
	 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
	 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
	 * has successfully completed and returned true.
	 */
	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

triggerAfterCompletion只會(huì)在(1)出現(xiàn)異常,(2)preHandle返回false 或(3)正常執(zhí)行結(jié)束才會(huì)從索引interceptorIndex依次往前執(zhí)行。

所以基于以上源碼可以得知,在寫攔截器時(shí)preHandle返回false時(shí),afterCompletion是不會(huì)執(zhí)行的。所以一些必要的清理工作得不到執(zhí)行,會(huì)出現(xiàn)類似我們遇到的帳號(hào)串的問(wèn)題。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • java wagon如何打包文件到不同服務(wù)器

    java wagon如何打包文件到不同服務(wù)器

    這篇文章主要介紹了java wagon如何打包文件到不同服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-06-06
  • @PathVariable注解,讓spring支持參數(shù)帶值功能的案例

    @PathVariable注解,讓spring支持參數(shù)帶值功能的案例

    這篇文章主要介紹了@PathVariable注解,讓spring支持參數(shù)帶值功能的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • Java高并發(fā)場(chǎng)景下的 HttpClient請(qǐng)求優(yōu)化實(shí)現(xiàn)

    Java高并發(fā)場(chǎng)景下的 HttpClient請(qǐng)求優(yōu)化實(shí)現(xiàn)

    本文主要介紹了Java高并發(fā)場(chǎng)景下的 HttpClient請(qǐng)求優(yōu)化實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • Java集合框架ArrayList源碼分析(一)

    Java集合框架ArrayList源碼分析(一)

    這篇文章主要為大家詳細(xì)介紹了Java集合框架ArrayList源碼分析,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 使用Java計(jì)算屏幕的PPI的方法詳解

    使用Java計(jì)算屏幕的PPI的方法詳解

    在現(xiàn)代電子設(shè)備中,屏幕的分辨率和顯示效果是用戶非常關(guān)注的一個(gè)指標(biāo),PPI(Pixels Per Inch,每英寸像素?cái)?shù))是衡量屏幕顯示精度的重要參數(shù)之一,PPI越高,屏幕顯示的圖像越細(xì)膩,視覺(jué)效果越好,本文將詳細(xì)介紹PPI的概念、計(jì)算方法,并通過(guò)Java代碼實(shí)現(xiàn)PPI的計(jì)算
    2025-02-02
  • 詳解mybatis中的if-else的嵌套使用

    詳解mybatis中的if-else的嵌套使用

    本文主要介紹了mybatis中的if-else的嵌套使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • springboot整合shiro實(shí)現(xiàn)記住我功能

    springboot整合shiro實(shí)現(xiàn)記住我功能

    這篇文章主要介紹了springboot整合shiro實(shí)現(xiàn)記住我功能,配置類 ShiroConfig,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-10-10
  • SpringBoot模擬員工數(shù)據(jù)庫(kù)并實(shí)現(xiàn)增刪改查操作

    SpringBoot模擬員工數(shù)據(jù)庫(kù)并實(shí)現(xiàn)增刪改查操作

    這篇文章主要給大家介紹了關(guān)于SpringBoot模擬員工數(shù)據(jù)庫(kù)并實(shí)現(xiàn)增刪改查操作的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-09-09
  • RxJava2 Scheduler使用實(shí)例深入解析

    RxJava2 Scheduler使用實(shí)例深入解析

    這篇文章主要為大家介紹了RxJava2 Scheduler使用實(shí)例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • SpringCloud Zuul實(shí)現(xiàn)動(dòng)態(tài)路由

    SpringCloud Zuul實(shí)現(xiàn)動(dòng)態(tài)路由

    這篇文章主要介紹了SpringCloud Zuul實(shí)現(xiàn)動(dòng)態(tài)路由,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01

最新評(píng)論

繁昌县| 普兰店市| 柳州市| 申扎县| 澳门| 凤阳县| 舞阳县| 兴文县| 孝感市| 大田县| 新乐市| 综艺| 策勒县| 商都县| 建瓯市| 同江市| 凌源市| 曲麻莱县| 康定县| 瑞昌市| 灵寿县| 宁远县| 锡林郭勒盟| 巴彦淖尔市| 政和县| 海晏县| 安阳县| 伊宁市| 醴陵市| 乌恰县| 桐城市| 西畴县| 泰和县| 宁明县| 呼和浩特市| 甘谷县| 襄垣县| 蚌埠市| 崇阳县| 石棉县| 澄城县|