《SpringMVC從入門到放肆》4、SpringMVC配置式開發(處理器映射器)

上一篇咱們講解了DispatcherServlet的url-pattern配置詳解,今天咱們來真正對SpringMVC進行配置式開發。
所謂配置式開發是指「處理器類是程序員本身定義的、實現了特定接口的類,而後在SpringMVC配置文件中對該類進行顯式的,明確的註冊」的開發方式。今天咱們的開發仍是將中央調度器的url-pattern配置成*.do。而後將springmvc.xml的靜態資源訪問先取消。程序員

1、處理器映射器(BeanNameUrlHandlerMapping)
handlerMapping接口負責根據request請求找到對應的Handler處理器及Interceptor攔截器,並將它們封裝在HandlerExecutionChain對象中,返回給中央調度器。其經常使用的實現類有兩種:
一、BeanNameUrlHandlerMapping
二、SimpleUrlHandlerMappingweb

這裏着重說明SimpleUrlHandlerMapping。BeanNameUrlHandlerMapping咱們簡單來看一下源碼:spring

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping { /** * Checks name and aliases of the given bean for URLs, starting with "/". */ @Override protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList<String>(); if (beanName.startsWith("/")) { urls.add(beanName); } String[] aliases = getApplicationContext().getAliases(beanName); for (String alias : aliases) { if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); } }

上方BeanNameUrlHandlerMapping類中只有一個方法determineUrlsForHandler()。該方法中把全部以斜槓開頭的請求的BeanName都放到了一個名叫urls的List中。而後返回給了中央調度器。可是有一個弊端,好比我有兩個請求都由一個Controller來處理,這時咱們的springmvc.xml文件的配置方式以下:spring-mvc

<!-- 註冊SpringMVC處理器 -->
<bean id="/my.do" class="cn.wechatbao.controller.MyController"></bean>
<bean id="/you.do" class="cn.wechatbao.controller.MyController"></bean>

這樣Spring容器在建立MyController實例的時候,一次性建立了兩個,而對於咱們來講,其實一個實例就能夠對兩個或多個請求進行處理。因此咱們繼續來說解SimpleUrlHandlerMapping方法。mvc

2、處理器映射器(SimpleUrlHandlerMapping)
要使用SimpleUrlHandlerMapping咱們須要將其註冊到SpringMVC中,如圖,咱們在默認的處理器映射器中並無發現該實現類。因此須要註冊。app

註冊方式:(springmvc.xml以下)cors

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    <!-- 註冊視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/my.do">myController</prop>
                <prop key="/you.do">myController</prop>
                <prop key="/he.do">myController</prop>
            </props>
        </property>
        <!-- 這種方式也能夠實現多個請求交由一個Controller處理的需求 <property name="urlMap"> <map> <entry key="/my.do" value="myController"></entry> <entry key="/you.do" value="myController"></entry> <entry key="/he.do" value="myController"></entry> </map> </property> -->
    </bean>
    
    <!-- 註冊SpringMVC處理器 -->
    <bean id="myController" class="cn.wechatbao.controller.MyController"></bean>
</beans>

注意:該種配置方式只針對多個請求用一個Controller處理才使用。jsp

 

3、處理器映射器源碼分析
一、當客戶端發送請求到達中央調度器(DispatcherServlet)時,DispatcherServlet首先進入到doService方法在doService()方法裏,對request設計一些屬性,而後又進入到了doDispatch()方法,在doDispatch()方法裏,咱們着重來看如下代碼:ide

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

二、從doDispatch()方法又進入了一個getHandler()的方法,以下源碼分析

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }

在該方法中,使用了一個forEach循環,來循環全部的處理器映射器,根據每一個處理器映射器(HandlerMapping)來獲取與之對應的處理器執行鏈(HandlerExecutionChain)。

進入hm.getHandler(request);方法來看。
三、繼續hm.getHandler(request);方法

@Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler?
    if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }

四、接下來又走到了HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);這個方法。咱們就不繼續深究了。有興趣的朋友能夠本身再研究下去。咱們得出的結論是通過了一系列的方法,最終返回給中央調度器一個HandlerExecutionChain對象。明白這個咱們的目的就已經達到了。

相關文章
相關標籤/搜索