SpringMVC原始碼分析系列:
- SpringMVC原始碼解析(1)-啟動過程
- SpringMVC原始碼解析(2)-DispatcherServlet
- SpringMVC原始碼解析(3)-HandleMapping
- SpringMVC原始碼解析(4)-HandlerAdapter
- SpringMVC原始碼解析(5)-HandlerExceptionResolver
- SpringMVC原始碼解析(6)-非同步請求
啟動過程
常見以web.xml配置方式
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>CtrTimeOut</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
# spring的配置
<param-value>classpath:config/spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
# springmvc的配置
<param-value>classpath:config/spring/spring-controller.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
複製程式碼
ContextLoadListener建立WebApplicationContext作為spring的容器上下文
#org.springframework.web.context.ContextLoader
/**
* 根據xml配置建立applicationContext
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
...
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {//判空 (以註解方式配置時非空)
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
...
//讀取contextConfigLocation配置並refresh()
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
//將applicationContext設定到servletContext中
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
...
return this.context;
}
}
複製程式碼
DispatcherServlet建立WebApplicationContext作為springmvc的上下文 並將ContextLoadListener建立的上下文設定為自身的parent
DispatcherServlet extends FrameworkServlet
#org.springframework.web.servlet.FrameworkServlet
@Override
protected final void initServletBean() throws ServletException {
...
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
...
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
...
if (wac == null) {
//建立applicationContext
wac = createWebApplicationContext(rootContext);
}
...
return wac;
}
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
//XmlWebApplicationContext
Class<?> contextClass = getContextClass();
...
//建立applicationContext
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
//設定parent(ContextLoadListener中建立的applicationContext)
wac.setParent(parent);
//讀取contextConfigLocation配置
wac.setConfigLocation(getContextConfigLocation());
//refresh()
configureAndRefreshWebApplicationContext(wac);
return wac;
}
複製程式碼
springmvc的applicationContext會去讀取配置檔案 我們來看一個最簡單的配置檔案
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
default-autowire="byName">
#springmvc容器掃描路徑
<context:component-scan base-package="com.iflytek.ossp.ctrtimeout.controller"></context:component-scan>
#spring4新增的標籤 主要是新增了預設的HandleMappin,ViewResolver,HandleAdapter
<mvc:annotation-driven />
</beans>
複製程式碼
springMvc配置解析
根據spring的自定義schema解析機制 我們找到 在下圖位置
http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
複製程式碼
可以看到mvc所有的標籤解析器都定義在此
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
}
}
複製程式碼
來看一下AnnotationDrivenBeanDefinitionParser解析器做了什麼
解析過程較為複雜 通過註釋我們可以得知以下物件將被裝載
DispatcherServlet呼叫過程
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//1.呼叫handlerMapping獲取handlerChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2.獲取支援該handler解析的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
// 3.使用HandlerAdapter完成handler處理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 4.檢視處理(頁面渲染)
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
...
}
複製程式碼
過程概括:
- 呼叫HandleMapping得到handler
- 呼叫HandleAdapter執行handle過程(引數解析 過程呼叫)
- 呼叫ViewResolver進行檢視解析
- 渲染檢視
上述圖片來自網路
HandleMapping
定義: 請求路徑-處理過程對映管理
打個比方就是根據你的http請求的路徑得到可以處理的handler(你的Controller方法)
/**
* Interface to be implemented by objects that define a mapping between
* requests and handler objects.
*/
public interface HandlerMapping {
//根據request獲取處理鏈
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
複製程式碼
以RequestMappingHandlerMapping為例 我們先看下他的繼承關係
可以看到有個InitlizingBean(spring的生命週期介面)我們就由他入手
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
//1.
@Override
public void afterPropertiesSet() {
if (this.useRegisteredSuffixPatternMatch) {
this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions());
}
super.afterPropertiesSet();
}
//4.
@Override
protected boolean isHandler(Class<?> beanType) {
return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
(AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
}
//6.
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = null;
RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
if (methodAnnotation != null) {
//組裝對映資訊
RequestCondition<?> methodCondition = getCustomMethodCondition(method);
info = createRequestMappingInfo(methodAnnotation, methodCondition);
RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
if (typeAnnotation != null) {
RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
}
}
return info;
}
#org.springframework.web.servlet.handler.AbstractHandlerMethodMapping
//2.
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
//3.
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//從容器中獲取所有object型別名
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
//抽象,過濾(在RequestMappingHandlerMapping中根據Controller和RequestMapping註解過濾)
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
isHandler(getApplicationContext().getType(beanName))){
//探測類中定義的handler方法
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
//5.
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType =
(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//得到符合條件的handler方法
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
@Override
public boolean matches(Method method) {
//抽象,得到對映資訊(如RequestMappingInfo)
T mapping = getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
}
else {
return false;
}
}
});
//註冊handler方法
for (Method method : methods) {
registerHandlerMethod(handler, method, mappings.get(method));
}
}
複製程式碼
上述程式碼就是HandlerMapping初始化對映關係的程式碼
過程概括:
- 獲取所有object子類
- 根據條件過濾出handle處理類
- 解析handle類中定義的處理方法
- 儲存解析得出的對映關係
來看一下getHandler(Request)的方法實現,看看DispatcherServlet是如何得到處理鏈的
#org.springframework.web.servlet.handler.AbstractHandlerMapping
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//抽象,呼叫子類實現得到一個handler(可以是任一物件,需要通過HandleAdapter來解析)
//RequestMappingInfoHandlerMapping中具體實現就是匹配請求路徑和RequestMapping註解
Object handler = getHandlerInternal(request);
...
//包裝handle成HandlerExecutionChain
return getHandlerExecutionChain(handler, request);
}
複製程式碼
HandleAdapter
定義: 根據HandlerMapping.getHandler()得到的Handler資訊,對http請求引數解析並繫結
先看一下HandlerAdapter的介面定義
public interface HandlerAdapter {
//判斷是否支援該handler型別的解析
boolean supports(Object handler);
//引數解析 並呼叫handler完成過程呼叫
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//用於處理http請求頭中的last-modified
long getLastModified(HttpServletRequest request, Object handler);
}
複製程式碼
以RequestMappingHandlerAdapter為例來講,先看下繼承關係
同樣看到了實現了InitializingBean介面 從這入手
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
public void afterPropertiesSet() {
// 1.初始化ControllerAdvice註解的物件
initControllerAdviceCache();
// 2.裝載ArgumentResolver(預設+自定義)
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
//包裝成一個Composite物件
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 2.裝載InitBinderArgumentResolvers(預設+自定義)
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
//包裝成一個Composite物件
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 3.裝載ReturnValueHandlers(預設+自定義)
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
//包裝成一個Composite物件
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private void initControllerAdviceCache() {
//從容器中獲取所有帶有ControllerAdvices註解的類名 幷包裝成ControllerAdviceBean
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
OrderComparator.sort(beans);
List<Object> responseBodyAdviceBeans = new ArrayList<Object>();
for (ControllerAdviceBean bean : beans) {
//篩選出帶有ModelAttribute且不帶RequestMapping註解的方法
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
//儲存到map中
this.modelAttributeAdviceCache.put(bean, attrMethods);
}
//篩選出帶InitBinder註解的方法
Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
//儲存到map中
this.initBinderAdviceCache.put(bean, binderMethods);
}
//如果該類同時實現了ResponseBodyAdvice介面 新增到結合中
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
responseBodyAdviceBeans.add(bean);
}
}
//儲存到全域性變數中
if (!responseBodyAdviceBeans.isEmpty()) {
this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
}
}
複製程式碼
過程概括:
- 裝載帶有ControllerAdvices註解的物件
- 裝載ArgumentResolvers(預設+自定義)
- 裝載InitBinderArgumentResolvers(預設+自定義)
- 裝載ReturnValueHandlers(預設+自定義)
自定義擴充方式放後面說
以下為HandlerAdapter預設解析器
看一下HandlerMethodReturnValueHandler介面和HandlerMethodArgumentResolver介面
//引數解析器
public interface HandlerMethodArgumentResolver {
//判斷是否支援該引數的解析(根據型別,註解等)
boolean supportsParameter(MethodParameter parameter);
//對引數進行解析 得到解析結果
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
//返回值解析器
public interface HandlerMethodReturnValueHandler {
//判斷是否支援該返回值的解析(根據型別,註解等)
boolean supportsReturnType(MethodParameter returnType);
//對返回值進行解析
void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
複製程式碼
上述即HandlerAdapter的初始化過程
DispatcherServlet呼叫HandlerAdapter過程
//1.呼叫support()方法判斷是否支援改handler的解析
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 如果是Get或Head請求 呼叫getLastModified()獲取上次更新時間
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
//如果小於瀏覽器快取更新時間 則直接返回 瀏覽器使用本地快取
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
複製程式碼
DisPatcherServlet呼叫HandlerAdapter分為三步:
- 呼叫support()方法判斷是否支援改handler的解析
#org.springframework.web.servlet.DispatcherServlet
//在doDispatch()方法中呼叫了getHandlerAdapter(Object)方法來得到一個HandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//呼叫HandlerAdapter.support()方法 判斷是否支援該handler物件的解析
for (HandlerAdapter ha : this.handlerAdapters) {
...
if (ha.supports(handler)) {
return ha;
}
}
...
}
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
複製程式碼
- 如果是Get或Head請求 呼叫getLastModified()獲取上次更新時間
如果小於瀏覽器快取更新時間 則直接返回 瀏覽器使用本地快取
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return -1;
}
複製程式碼
- 呼叫handler()方法完成過程呼叫(引數解析 返回值解析)
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//對http協議快取方面的請求頭的處理(expire,cache-control)
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// Always prevent caching in case of session attribute management.
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
// Uses configured default cacheSeconds setting.
checkAndPrepare(request, response, true);
}
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {//是否使用session鎖
HttpSession session = request.getSession(false);
if (session != null) {
//得到互斥量
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {//執行過程呼叫
return invokeHandleMethod(request, response, handlerMethod);
}
}
}
//執行過程呼叫
return invokeHandleMethod(request, response, handlerMethod);
}
//根據HandlerMethod解析引數 並完成過程呼叫得到一個ModelAndView
private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//使用initBinderAdviceCache對@initBinder進行處理
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 使用modelAttributeAdviceCache對@ModelAttribute進行處理
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//對非同步的處理 暫時不管 TODO後面再分析
...
//1 完成過程呼叫
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
//2 包裝ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
複製程式碼
handle()過程總結:
- 執行過程呼叫requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
#org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1.1 引數解析 並完成過程呼叫
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
...
try {
//1.2 使用returnValueHandlers對返回結果進行處理 講結果塞到mavContainer中 過程類似引數解析
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
}
#org.springframework.web.method.support.InvocableHandlerMethod
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//1.1.1 引數解析並得到繫結的結果
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
...
//1.1.2 反射完成過程呼叫
Object returnValue = doInvoke(args);
...
return returnValue;
}
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//引數資訊
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
//呼叫HandlerMethodArgumentResolver#supportsParameter判斷是否支援
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
//呼叫HandlerMethodArgumentResolver#resolveArgument進行解析
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
...
}
...
}
return args;
}
複製程式碼
- 包裝ModelAndView getModelAndView(mavContainer, modelFactory, webRequest);
//從mavContainer取出結果 包裝成ModelAndView
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//如果是redirect請求
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
複製程式碼
到此 HandlerAdapter的呼叫過程算分析完了