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的各个重要的技术,须要必定的基础再去看比较好,值得推荐。

相关文章
相关标签/搜索