spring MVC -- controller參數的解析

spring給咱們帶來了什麼?前端

spring IoC、AOP、Transaction這些都是很重要的特性,可是這篇這些都不是主角,主要來談談springMVC是如何對請求參數進行解析封裝的,以及簡單的介紹spring是怎麼進行http請求路由的。java

0x01 springMVC工程的創建

本篇就不過多介紹springMVC的工程的新建過程,這次調試springMVC源碼新建的工程目錄以下,經過maven管理的工程:
圖片描述web

0x02 spring是如何接入web容器的

在進行springMVC的開發過程當中咱們都會在web.xml文件中進行下面一些配置,可是這些配置都是用來幹嗎的呢?spring

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <!-- Spring配置 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:config/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- logback配置 LogbackConfigListener由logback-ext-spring提供 -->
    <context-param>
        <param-name>logbackConfigLocation</param-name>
        <param-value>classpath:logconfig/logback.xml</param-value>
    </context-param>
    <listener>
        <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
    </listener>

    <!-- Spring MVC配置 -->
    <servlet>
        <servlet-name>springMvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:config/applicationMvcContext.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

這裏着重介紹ContextLoaderListener和DispatcherServlet。瀏覽器

  1. ContextLoaderListener是spring提供的類,爲了在web容器中創建IoC容器而服務的。它實現了ServletContextListener這個接口,經過這個接口的方法實現servlet生命週期的回調,在這個過程當中會經過XmlWebApplicationContext去加載bean的配置建立IoC容器。app

  2. DispatcherServlet做爲一個前端控制器,他會去加載另外一個bean的配置造成一個IoC容器,這個IoC會將ContextLoaderListener加載的IoC容器做爲父容器,這樣的好處是從DispatcherServlet容器中getBean也能取到父容器中的bean,他會先去父容器中看有沒有,若是找到直接返回了。DispatcherServlet 主要處理HTTP的請求分發(HandlerMapping),對controller、viewresolver、view進行管理。DispatcherServlet接收到請求由HandlerMapping進行匹配,匹配成功後交由controller進行業務邏輯的處理,業務邏輯處理完成後交由viewresolver進行數據的解析同時找到對應的view,最終由DispatcherServlet將view的結果render到瀏覽器進行解析。maven

0x03 controller的參數是如何被解析的

  • 在開發過程當中遇到下面這樣的controller方法怎麼也獲得不到us值,函數

    public String printWelcome(ModelMap model,ArrayList<String> us){}學習

  • 若是改爲下面這樣就能夠正常獲得us的值url

    public String printWelcome(ModelMap model,String us){}

這是爲何?怎麼解決?

  • 搜索後發現這樣能夠解決問題,可是sowhat?

    public String printWelcome(ModelMap model,@RequestParam("us[]") List<String> us){}

  • 因此須要來剖析下springMVC的源代碼了,發現spring是經過下面這個方法進行controller參數解析的。

    org.springframework.web.bind.annotation.support.HandlerMethodInvoker#resolveHandlerArguments

解析參數值的代碼(裏面好多if else啊):
圖片描述

從這個圖片能夠看到經過if去判斷paramName對應controller方法中的@RequestParam,pathVarName對應@PathVariable,沒有加任何修飾會進入到attrName這個分支裏面去解析參數。在解析的過程當中會經過函數的參數類型去組裝對象傳遞到RequestMapping類的方法中。

  • 若是是下面這樣的方法參數又會怎樣

    public String printWelcome(ModelMap model,@RequestParam("us[]") List<User> us){}

  • User是自定義的參數,spring會對這種參數進行一個特殊的處理處理方法以下:

    org.springframework.beans.TypeConverterDelegate#convertIfNecessary

在這個方法中有一段處理的代碼,會根據List內部元素類型去判斷類型是不許確並賦值。
圖片描述

到這裏應該和controller相關的註解能夠隨便用了吧?

0x04 感想

在學校期間一直用着C、C++進行開發,其實也沒怎麼開發,只是做爲裝逼的一種手段,現在踏入工做崗位開始離C、C++很遠了,又開始了0基礎JAVA開發。做爲一個門外漢來觀望spring。
spring的東西太多了,也很權威你們基本上都用,因此後面還學要增強這方面的探索和學習,期待後面本身還能將spring的學習感想記錄下來。這篇是在進行開發的過程當中遇到上面提到的一個問題因此想深刻了解其背後的實現方式,將來繼續spring。

0x05 參考

在學習spring的過程當中能夠參考計文柯著的spring技術內幕,裏面結合代碼講解了spring的各個重要的技術,須要必定的基礎再去看比較好,值得推薦。

相關文章
相關標籤/搜索