<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringMVC系列 教程(六):攔截器詳解(附源碼分析)

          共 5265字,需瀏覽 11分鐘

           ·

          2019-12-08 23:29

          4cd04569e7479d867ace99272486dcc0.webp

          7f99125a93988f36d638789f03ec06fa.webp

          來源:https://www.cnblogs.com/

          fangjian0423/p/springMVC-interceptor.html

          一.?前言

          SpringMVC是目前主流的Web MVC框架之一。?

          攔截器是每個Web框架必備的功能,也是個老生常談的主題了。

          本文將分析SpringMVC的攔截器功能是如何設(shè)計的,讓讀者了解該功能設(shè)計的原理。

          二.?重要接口及類介紹


          1.?HandlerExecutionChain類

            由HandlerMethod和Interceptor集合組成的類,會被HandlerMapping接口的getHandler方法獲取。

          bdb1765daa923446f7799d02bd77bfeb.webp

          2.?HandlerInterceptor接口

            a453ffd26a08f7f9b489fefeecdefc3f.webp

            SpringMVC攔截器基礎(chǔ)接口。 

          3. AbstractHandlerMapping

            HandlerMapping的基礎(chǔ)抽象類。

          fab1159285561de83599e93097ef48bb.webp

          4.?AsyncHandlerInterceptor

            繼承HandlerInterceptor的接口,額外提供了afterConcurrentHandlingStarted方法,該方法是用來處理異步請求。當(dāng)Controller中有異步請求方法的時候會觸發(fā)該方法。樓主做過測試,異步請求先支持preHandle、然后執(zhí)行afterConcurrentHandlingStarted。異步線程完成之后執(zhí)行preHandle、postHandle、afterCompletion。有興趣的讀者可自行研究。

          5.?HandlerInterceptorAdapter

          ?  實現(xiàn)AsyncHandlerInterceptor接口的抽象類,一般我們使用攔截器的話都會繼承這個類。然后復(fù)寫相應(yīng)的方法。

          6. WebRequestInterceptor

            與HandlerInterceptor接口類似,區(qū)別是WebRequestInterceptor的preHandle沒有返回值。還有WebRequestInterceptor是針對請求的,接口方法參數(shù)中沒有response。

            fdf6a0649cb9e1bacad28792f7ec836d.webp

            AbstractHandlerMapping內(nèi)部的interceptors是個Object類型集合。處理的時候判斷為MappedInterceptor[加入到mappedInterceptors集合中];HandlerInterceptor、WebRequestInterceptor(適配成WebRequestHandlerInterceptorAdapter)[加入到adaptedInterceptors中]

          7. MappedInterceptor

            一個包括includePatterns和excludePatterns字符串集合并帶有HandlerInterceptor的類。很明顯,就是對于某些地址做特殊包括和排除的攔截器。

          ?  e9ec1ec5acfa3f2a42096e5b95a137e0.webp

          8. ConversionServiceExposingInterceptor

            默認(rèn)的標(biāo)簽初始化的時候會初始化ConversionServiceExposingInterceptor這個攔截器,并被當(dāng)做構(gòu)造方法的參數(shù)來構(gòu)造MappedInterceptor。之后會被加入到AbstractHandlerMapping的mappedInterceptors集合中。該攔截器會在每個請求之前往request中丟入ConversionService。主要用于spring:eval標(biāo)簽的使用。

          三. 源碼分析


          首先我們看下攔截器的如何被調(diào)用的。

          Web請求被DispatcherServlet截獲后,會調(diào)用DispatcherServlet的doDispatcher方法。

          fc0ca00f12c3d43ea8022ad7f5872786.webp

          c57147af1909214382ce308453b02cfc.webp

          很明顯地看到,在HandlerAdapter處理之后,以及處理完成之后會調(diào)用HandlerExecutionChain的方法。

          HandlerExecutionChain的applyPreHandle、applyPostHandle、triggerAfterCompletion方法如下:

          edee00ec52d859b86b1402ffac15cec4.webp

          24f1399e995b8a88c752164db2922ed6.webp

          ee1873198135216ba192a5362c65c991.webp

          很明顯,就是調(diào)用內(nèi)部實現(xiàn)HandlerInterceptor該接口集合的各個對應(yīng)方法。

          ?

          下面我們看下HandlerExecutionChain的構(gòu)造過程。

          ?HandlerExecutionChain是從HandlerMapping接口的getHandler方法獲取的。

          ?HandlerMapping的基礎(chǔ)抽象類AbstractHandlerMapping中:

          1e483b4a98b2ee6b3f09a5d25c977801.webp

          7c8e435ef66e7b6c4412ef9ea1600384.webp

          我們看到,HandlerExecutionChain的攔截器是從AbstractHandlerMapping中的adaptedInterceptors和mappedInterceptors屬性中獲取的。

          四.?攔截器的配置


          清楚了HandlerExecutionChain的攔截器屬性如何構(gòu)造之后,下面來看下SpringMVC是如何配置攔截器的。

          1. *-dispatcher.xml配置文件中添加?配置

          <mvc:interceptors>  <mvc:interceptor>    <mvc:mapping path="/**"/>    <mvc:exclude-mapping path="/login"/>       <mvc:exclude-mapping path="/index"/>    <bean class="package.interceptor.XXInterceptor"/>  mvc:interceptor>mvc:interceptors>

          這里配置的每個都會被解析成MappedInterceptor。

          其中子標(biāo)簽會被解析成MappedInterceptor的includePatterns屬性;會被解析成MappedInterceptor的excludePatterns屬性;會被解析成MappedInterceptor的interceptor屬性。

          這個標(biāo)簽是被InterceptorsBeanDefinitionParser類解析。

          d167d203e346efc4d24638089d269e54.webp

          2. 配置RequestMappingHandlerMapping,并配置該bean對應(yīng)的interceptors集合屬性。這里的interceptors集合是個Object類型的泛型集合。

            AbstractHandlerMapping抽象類只暴露了1個攔截器的set方法 -> interceptors。

            adaptedInterceptors和mappedInterceptors均沒有暴露set方法,因此我們只能為RequestMappingHandlerMapping配置interceptors屬性。

            其實AbstractHandlerMapping內(nèi)部的initInterceptors方法中,會遍歷interceptors集合,然后判斷各個項是否是MappedInterceptor、HandlerInterceptor、WebRequestInterceptor。

            其中MappedInterceptor類型的攔截器會被加到mappedInterceptors集合中,HandlerInterceptor類型的會被加到adaptedInterceptors集合中,WebRequestInterceptor類型的會被適配成WebRequestHandlerInterceptorAdapter加到adaptedInterceptors集合中。

            1cab3da2c248aab1ac856938d375defb.webp

            0c52e098edb71db36084dabc8b281a59.webp

            如果讀者配置了:

            那么配置如下:

          class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">  <property name="interceptors">    <bean class="package.interceptor.XXInterceptor"/>  property>    <property name="order" value="-1"/>bean>

            否則,可以去掉order這個屬性的設(shè)置。

            一般建議使用第一種方法。 

          五. 編寫自定義的攔截器
          public class LoginInterceptor extends HandlerInterceptorAdapter {  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response,                             Object handler) throws Exception {        // 獲得請求路徑的uri        String uri = request.getRequestURI();
          // 判斷路徑是登出還是登錄驗證,是這兩者之一的話執(zhí)行Controller中定義的方法 if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) { return true; }
          // 進入登錄頁面,判斷session中是否有key,有的話重定向到首頁,否則進入登錄界面 if(uri.endsWith("/login/") || uri.endsWith("/login")) { if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) { response.sendRedirect(request.getContextPath() + "/index"); } else { return true; } }
          // 其他情況判斷session中是否有key,有的話繼續(xù)用戶的操作 if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) { return true; }
          // 最后的情況就是進入登錄頁面 response.sendRedirect(request.getContextPath() + "/login"); return false; }}

          登錄Controller:

          @Controller@RequestMapping(value = "/login")public class LoginController {    @RequestMapping(value = {"/", ""})    public String index() {        return "login";    }
          @RequestMapping("/auth") public String auth(@RequestParam String username, HttpServletRequest req) { req.getSession().setAttribute("loginUser", username); return "redirect:/index"; }
          @RequestMapping("/out") public String out(HttpServletRequest req) { req.getSession().removeAttribute("loginUser"); return "redirect:/login"; }}

          ?*-diapatcher.xml配置:

          <mvc:interceptors>  <mvc:interceptor>    <mvc:mapping path="/**"/>    <bean class="org.format.demo.interceptor.LoginInterceptor"/>  mvc:interceptor>mvc:interceptors>

          PS:我們看到LoginInterceptor里的preHandle方法對于地址“/login/auth”和"/login/out"不處理。

          因此,可以寫點配置,少寫帶java代碼。在攔截器配置中添加2個exclude-mapping,并且去掉LoginInterceptor里的

          if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) {  return true;}

          配置新增:

          <mvc:exclude-mapping path="/login/out"/><mvc:exclude-mapping path="/login/auth"/>

          六. 小結(jié)


          總結(jié)了SpringMVC攔截器的原理以及各種配置,像網(wǎng)上很多人會問為什么攔截器執(zhí)行preHandle方法返回false之后還是會執(zhí)行afterCompletion方法,其實我們看下源碼就知道了。

          關(guān)于異步請求方面的攔截器以及第二種配置方法(interceptors集合屬性可加入繼承自HandlerInterceptorAdapter抽象類的類以及實現(xiàn)WebRequestInterceptor接口的類),讀者可自行研究。

          文中難免有錯誤,希望讀者能夠指出來。


          - End -

          ed0b022a3d073ff6f0979d0734708fad.webp

          術(shù)轉(zhuǎn)


          面試題系列教程??點擊-->?面試題技術(shù)干貨連載目錄?跳轉(zhuǎn)


          Maven系列教程??點擊-->?Maven技術(shù)干貨連載目錄?跳轉(zhuǎn)


          MyBatis系列教程??點擊-->?MyBatis技術(shù)干貨連載目錄?跳轉(zhuǎn)


          JVM調(diào)優(yōu)總結(jié)系列教程??點擊-->?JVM調(diào)優(yōu)技術(shù)干貨連載目錄?跳轉(zhuǎn)





          ,?a514e826b619d8e428016d74ac0ea58b.webp

          瀏覽 175
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费黄片视频在线观看 | 婷婷国产精品视频 | 欧美操逼操逼操 | 国产人人色| 蜜臀视频网站狠狠操b |