Spring MVC流程

SpringMVC启动流程

启动流程

  1. 启动Tomcat

  2. 解析web.xml

  3. 创建DispatcherServlet

  4. 调用DIspatcherServlet的init方法
    4.1 创建Spring容器
    4.2 发布ContextRefresheEvent
    4.3 在OnRefreshed方法中触发initStrategies方法
    4.3.1初始化HandlerMappings (RequestMappingHandler会把@RequestMappping标注的方法解析为HandlerMapping Map<path, 注解信息>, Map<注解信息,方法>)
    4.3.2 初始化HandlerAdapters(不同handler使用不同的Adapter)
    4.3.3 初始化Resolvers...

    默认添加的Handler和Adapter在DispatcherServlet.properties文件中

    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

父子容器

servlet会根据配置文件spring-mvc.xml生成子容器。

复制代码
    <!-- 配置 Spring MVC 的 DispatcherServlet -->
    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- 配置 DispatcherServlet 的 URL 映射 -->
    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>

如何需要父容器,需要如下配置。

Tomcat会先解析listener,根据配置spring.xml生成父容器,子容器可以使用父容器中的Bean。实际应用中其实一个容器就够了。即只使用servlet中的容器。

复制代码
    <!-- 配置 Spring 上下文监听器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:srping.xml</param-value>
    </context-param>

    <!-- 配置 Spring 的 ContextLoaderListener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

请求处理

请求是通过DispatcherServlet的doDispatch方法处理。根据path得到handler后处理请求。Adapter处理请求时需要使用Resolver解析参数传递到方法中,方法执行后还需要使用HttpMessageConverter处理返回值转换。

MultipartFile 解析

doDispatch方法在找handler之前会先判断是否是表单文件上传。通过request的Content-Type: mulpart/form-data来判断是MultipartFile,然后MulpartResolver把表单数据解析为multipartFiles,结构为map<filename, standardMultipartFile>。然后会把MultipartFile传到请求的处理方法中。

因此需要配置MultipartFile的Resolver。

复制代码
<multipart-config>
   <location>/tmp</location> <!-- 临时文件存储路径 -->
   <max-file-size>10485760</max-file-size> <!-- 单个文件最大 10MB -->
   <max-request-size>20971520</max-request-size> <!-- 整个请求最大 20MB -->
   <file-size-threshold>1048576</file-size-threshold> <!-- 超过 1MB 的文件写入磁盘 -->
</multipart-config>
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" />

参数传递

在 Spring MVC 中,参数处理器(HandlerMethodArgumentResolver)用于将 HTTP 请求中的参数绑定到控制器方法的参数上。

@RequestParam:RequestParamMethodArgumentResolver从request中取param

@PathVariabl:PathVariableMethodArgumentResolver将 URL 路径中的变量绑定到方法参数

@RequestBody:RequestResponseBodyMethodProcessor

@RequestPart:将 multipart 请求中的文件或复杂对象绑定到方法参数。

@RequestHeader:RequestHeaderMethodArgumentResolver将 HTTP 请求头绑定到方法参数

无注解的简单类型:取request与参数名称相同的param

无注解对象类型参数:ModelAttributeMethodProcessor会先调用对象的无参构造器生成一个对象,然后会根据属性名称取param中取参数。如果只有一个属性,即使名称不一致也能赋值。

返回值处理

HttpMessageConverter通过方法返回的类型+Accept接收的格式来确定能否处理。默认提供的HttpMessageConverter只有StringHttpMessageConverter和ByteArrayHttpMessageConverter。因此复杂对象需要引入MappingJackson2HttpMessageConverter。也可以自己定义转换器,通过@InitBinder绑定对象和使用的转换器。

HandlerInterceptor

handlerInterceptor可以在handler处理请求前后添加处理逻辑。

preHandle:请求方法调用之前执行,如果出现错误则停止不执行请求方法。

postHandle:请求方法调用之后执行

afterCompletion:总会执行

相关推荐
wfsm30 分钟前
spring事件使用
java·后端·spring
Exclusive_Cat4 小时前
SpringMVC参数接收与数据返回详解
spring·mvc
ChinaRainbowSea5 小时前
补充:问题:CORS ,前后端访问跨域问题
java·spring boot·后端·spring
hqxstudying7 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
春生野草8 小时前
关于SpringMVC的整理
spring
Bug退退退1238 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
hello早上好9 小时前
CGLIB代理核心原理
java·spring
先睡16 小时前
Redis的缓存击穿和缓存雪崩
redis·spring·缓存
Bug退退退12320 小时前
RabbitMQ 高级特性之死信队列
java·分布式·spring·rabbitmq
booooooty1 天前
基于Spring AI Alibaba的多智能体RAG应用
java·人工智能·spring·多智能体·rag·spring ai·ai alibaba