1. 程式人生 > >SpringMVC原始碼學習(四)九大元件

SpringMVC原始碼學習(四)九大元件

1. HandlerMapping

在dispatcherServlet,doDispatch方法中有呼叫getHandler,程式碼如下: 
其中List< HandlerMapping> handlerMappings是dispatcherServlet的內部變數。 
那該方法的內容就是遍歷handlerMappings,獲得符合條件的HandlerMapping,呼叫其getHandler方法,返回獲得的HandlerExecutionChain

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> HandlerExecutionChain <span class="hljs-title" style="box-sizing: border-box;">getHandler</span>(HttpServletRequest request) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (HandlerMapping hm : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.handlerMappings) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isTraceEnabled()) {
                logger.trace(
                        <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Testing handler map ["</span> + hm + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"] in DispatcherServlet with name '"</span> + getServletName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"'"</span>);
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (handler != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> handler;
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

HandlerMapping是一個介面,內部只有一個方法和諾幹變數,它的作用是根據request找到對應的Handler。方法如下: 
HandlerExecutionChain getHandler(HttpSevletRequest request) throws Exception 
接下來看看一個該方法的實現,SimpleControllerHandlerAdapter,程式碼如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> HandlerExecutionChain <span class="hljs-title" style="box-sizing: border-box;">getHandler</span>(HttpServletRequest request) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception {
        Object handler = getHandlerInternal(request);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (handler == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
            handler = getDefaultHandler();
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (handler == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
        }
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Bean name or resolved handler?</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (handler <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }

        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.corsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> executionChain;
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

另外一個要討論的就是順序問題,不同hander負責對映的條件可能有重複的,這時候就需要定義不同的HandlerMapping執行的順序,這裡的順序可以通過實現Order介面,通過Order屬性定義。order越小越先使用。如:

<code class="language-xml hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">bean</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">class</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"com.excelib.TudouHandlerMapping"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">p:order</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"1"</span>/></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">bean</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">class</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"com.excelib.TudoupianHandlerMapping"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">p:order</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"0"</span>/></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

2.HandlerAdapter

在dispatcherServlet通過如下方法獲得HandlerAdapter,其中List< HandlerAdapter> handlerAdapters是dispatcherServlet的成員變數,可以看到它的邏輯是遍歷所有的Adapter,然後檢查哪個可以處理當前的Handler,找到第一個可以處理Handler的Adapter後停止查詢,返回。這裡的順序同樣是通過Order屬性設定的。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> HandlerAdapter <span class="hljs-title" style="box-sizing: border-box;">getHandlerAdapter</span>(Object handler) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> ServletException {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (HandlerAdapter ha : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.handlerAdapters) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isTraceEnabled()) {
                logger.trace(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Testing handler adapter ["</span> + ha + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>);
            }
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ha.supports(handler)) {
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ha;
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ServletException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No adapter for handler ["</span> + handler +
                <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"</span>);
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

上篇文章有介紹,HandlerAdapter的角色是使用工具(handler)的人。因為handler是Object型別,需要HandlerAdapter使用它來完成一定格式要求的任務。 
它是一個介面,程式碼如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">HandlerAdapter</span> {</span>   
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> supports(Object handler);   
        ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception;
       <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> getLastModified(HttpServletRequest request, Object handler);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

接下來看一個spring自己實現的示例,程式碼如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">SimpleControllerHandlerAdapter</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">HandlerAdapter</span> {</span>

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">supports</span>(Object handler) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (handler <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> Controller);
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> ModelAndView <span class="hljs-title" style="box-sizing: border-box;">handle</span>(HttpServletRequest request, HttpServletResponse response, Object handler)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception {

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ((Controller) handler).handleRequest(request, response);
    }

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-title" style="box-sizing: border-box;">getLastModified</span>(HttpServletRequest request, Object handler) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (handler <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> LastModified) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ((LastModified) handler).getLastModified(request);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>L;
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

可以看到這個Adapter比較簡單,它要求handler實現了Controller介面,方法的實現是通過處理器的handleRequest方法。

3. HandlerExceptionResolver

HandlerExceptionResolver是SpringMVC中專門負責處理異常的類。它負責: 
根據異常設定ModelAndView。 
之後交給render方法進行渲染。render只負責將Model渲染成頁面。具體ModelAndView的來源render並不關心。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">HandlerExceptionResolver</span> {</span>
    ModelAndView resolveException(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

它的結構很簡單,只有一個方法,只需要從異常解析出ModelAndView就可以了。具體實現可以維護一個異常為Key、View為value的Map,解析時直接從Map裡獲取View。

4.ViewResolver

ViewResolver用來將String型別的檢視名(也叫邏輯檢視)和Locale解析為View型別的檢視,ViewResolver介面也很簡單,程式碼如下

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ViewResolver</span> {</span>
    View resolveViewName(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception;

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

這裡可以看到引數是viewName和locale,不過一般我們只要根據檢視名找到檢視,然後渲染就可以,如果需要國際化支援也只要將顯示的內容或者主題使用國際化支援。 
View是用來渲染頁面的,也就是將程式返回的引數填入模板中,生成html或其他格式的檔案。所以說它會解決兩個問題: 
1. 填入哪個模板? 
2. 如何填入? 
它會找到渲染所用的模板和所用的技術(也就是檢視的型別)進行渲染,具體的渲染過程則交給不同的檢視自己完成。 
我們最常用的UrlBasedViewResolver系列的解析器都是針對單一檢視型別進行解析的。比如InternalResourceViewResolver只針對jsp型別的檢視,FreeMarkerViewResolver只針對FreeMarker,VelocityViewResolver只針對Velocity。而ResourceBundleViewResolver、XmlViewResolver、BeanNameViewResolver等解析器可以同時解析多種型別的檢視。 
ResourceBundleViewResolver使用properties配置檔案來進行配置解析的檔案類和url、XmlViewResolver使用xml配置。BeanNameViewResolver是根據ViewName從ApplicationContext容器中查詢相應的bean做View的,它比較簡單,原始碼如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">BeanNameViewResolver</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">WebApplicationObjectSupport</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ViewResolver</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Ordered</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> order = Integer.MAX_VALUE;  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// default: same as non-Ordered</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setOrder</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> order) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.order = order;
    }
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">getOrder</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.order;
    }
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> View <span class="hljs-title" style="box-sizing: border-box;">resolveViewName</span>(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> BeansException {
        ApplicationContext context = getApplicationContext();
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!context.containsBean(viewName)) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isDebugEnabled()) {
                logger.debug(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No matching bean found for view name '"</span> + viewName + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"'"</span>);
            }
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Allow for ViewResolver chaining...</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!context.isTypeMatch(viewName, View.class)) {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isDebugEnabled()) {
                logger.debug(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Found matching bean for view name '"</span> + viewName +
                        <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"' - to be ignored since it does not implement View"</span>);
            }
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Since we're looking into the general ApplicationContext here,</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// let's accept this as a non-match and allow for chaining as well...</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> context.getBean(viewName, View.class);
    }

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li></ul>

可以看出原理就是根據viewName從spring容器中查詢Bean,if(找不到||不是view型別) return null; else return context.getBean(viewName, View.class); 

ViewResolver的使用需要註冊到Spring MVC容器中,預設使用的是org.springframework.web.servlet.view.InternalResourceViewResolver。

5. RequestToViewNameTranslator

ViewResolver根據ViewName查詢View,但有的Handler處理完並沒有設定View,也沒有設定viewName,這時就需要從request中獲取viewName。也就是RequestToViewNameTranslator的任務。它是個介面,程式碼如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">RequestToViewNameTranslator</span> {</span>
    String getViewName(HttpServletRequest request) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

就像之前說的,他只有一個getViewName方法,能夠從request獲取到viewName就可以了。下面是一個簡單實現的示例:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(request.getRequestURI().toString().startsWith(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/todou"</span>)&&request.getMethod().equalsIgnoreCase(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"GET"</span>))
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"maidigua"</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"404"</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

RequestToViewNameTranslator在Spring MVC容器中只能配置一個,所以所有request到ViewName的轉換規則都要在一個Translator裡面實現。

6. LocaleResolver

還記得ViewResolver有兩個引數,viewname和Locale,viewname來自Handler或RequestToViewNameTranslator。locale變數就來自LocaleResolver。 
LocaleResolver用於從request解析出Locale。

Locale就是zh-cn之類的,表示一個區域。有了這個就可以對不同區域的使用者顯示不同的結果,這就是il18n(國際化)的基本原理。

LocaleResolver是個介面,程式碼如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">LocaleResolver</span> {</span>
    Locale resolveLocale(HttpServletRequest request);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale);

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

一共只有兩個方法,第一個方法就是起到獲取Locale的作用,在介紹doService方法時說過,容器會將localeResolver設定到request的attribute中。 
程式碼如下:

request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE,this.localeResolver);

切換Locale: 
第二個方法可以將Locale設定到request中。 
SpringMVC提供了統一修改request中Locale的機制,就是我們在分析doDispatch時見過的Interceptor。SpringMVC已經寫好現成的了,配置一下就可以,也就是org.springframework.web.servlet.i18n.LocaleChangeInterceptor. 
配置方法如:

<code class="language-xml hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">mvc:interceptors</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">mvc:interceptor</span>></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">mvc:mapping</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">path</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"/*"</span>/></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">bean</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">class</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"org.springframework.web.servlet.i18n.LocaleChangeInterceptor"</span>/></span>
        //這裡也可以自定義引數的名稱,如:
        //<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">bean</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">class</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"org.springframework.web.servlet.i18n.LocaleChangeInterceptor"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">p:paramName</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"lang"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">mvc:interceptor</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">mvc:interceptors</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

這樣通過request的locale引數就可以修改Locale了,如:http://localhost:8080?locale=zh_CN 
http://localhost:8080?locale=en 
用到Locale的地方有兩處,1、ViewResolver解析檢視的時候。2、使用到國際化資源或者主題的時候。國際化資源或主題主要使用RequestContext的getMessage和getThemeMessage方法。

7.ThemeResolver

它是個介面,原始碼如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ThemeResolver</span> {</span>
    String resolveThemeName(HttpServletRequest request);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

SpringMVC中一套主題對應一個properties檔案,裡面存放著跟當前主題相關的所有資源,如圖片、css樣式表等,如:

<code class="language-properties hljs haskell has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#theme.properties</span>
<span class="hljs-title" style="box-sizing: border-box;">logo</span>.pic=/images/<span class="hljs-default" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">default</span>/logo.jpg</span>
<span class="hljs-title" style="box-sizing: border-box;">logo</span>.word=excelib
<span class="hljs-title" style="box-sizing: border-box;">style</span>=/css/<span class="hljs-default" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">default</span>/style.css</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

SpringMVC跟主題有關的類主要有ThemeResolver、ThemeSource和Theme。 
1. ThemeResolver的作用是從request解析出主題名。 
2. ThemeSource的作用是根據主題名找到具體的主題。 
3. Theme是ThemeSource找出的一個具體的主題。 
看一下如下程式碼:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//org.springframework.web.servlet.support.RequestContext;</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> String <span class="hljs-title" style="box-sizing: border-box;">getThemeMessage</span>(String code, Object[] args, String defaultMessage) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> getTheme().getMessageSource().getMessage(code, args, defaultMessage, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.locale);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Theme <span class="hljs-title" style="box-sizing: border-box;">getTheme</span>() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.theme == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Lazily determine theme to use for this RequestContext.</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.theme = RequestContextUtils.getTheme(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.request);
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.theme == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// No ThemeResolver and ThemeSource available -> try fallback.</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.theme = getFallbackTheme();
            }
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.theme;
    }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//org.springframework.web.servlet.support.RequestContextUtils</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Theme <span class="hljs-title" style="box-sizing: border-box;">getTheme</span>(HttpServletRequest request) {
        ThemeResolver themeResolver = getThemeResolver(request);
        ThemeSource themeSource = getThemeSource(request);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (themeResolver != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && themeSource != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
            String themeName = themeResolver.resolveThemeName(request);
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> themeSource.getTheme(themeName);
        }
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>;
        }
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-