SpringMVC啟動流程
- 啟動流程
- 父子容器
- 請求處理
- MultipartFile 解析
- 參數傳遞
- 返回值處理
- HandlerInterceptor
啟動流程
- 啟動Tomcat
- 解析web.xml
- 創建DispatcherServlet
- 調用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.RequestMappingHandlerMappingorg.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:總會執行