SpringMVC源碼分析系列(精簡)

SpringMVC源碼分析系列:php

啓動過程

常見以web.xml配置方式java

<?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的容器上下文web

#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建立的上下文設置爲自身的parentspring

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解析機制 咱們找到 在下圖位置spring-mvc

http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
複製代碼

mvc標籤解析定義

能夠看到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解析器作了什麼bash

解析過程較爲複雜 經過註釋咱們能夠得知如下對象將被裝載網絡

annotation-driven

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);
	}
	...
}
複製代碼

過程歸納:session

  1. 調用HandleMapping獲得handler
  2. 調用HandleAdapter執行handle過程(參數解析 過程調用)
  3. 調用ViewResolver進行視圖解析
  4. 渲染視圖

springmvc流程
上述圖片來自網絡

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爲例 咱們先看下他的繼承關係

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初始化映射關係的代碼

過程歸納:

  1. 獲取全部object子類
  2. 根據條件過濾出handle處理類
  3. 解析handle類中定義的處理方法
  4. 保存解析得出的映射關係

來看一下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爲例來說,先看下繼承關係

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);
	}
}
複製代碼

過程歸納:

  1. 裝載帶有ControllerAdvices註解的對象
  2. 裝載ArgumentResolvers(默認+自定義)
  3. 裝載InitBinderArgumentResolvers(默認+自定義)
  4. 裝載ReturnValueHandlers(默認+自定義)

自定義拓展方式放後面說

如下爲HandlerAdapter默認解析器

RequestHandlerAdapter

看一下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分爲三步:

  1. 調用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;
}
複製代碼
  1. 若是是Get或Head請求 調用getLastModified()獲取上次更新時間

若是小於瀏覽器緩存更新時間 則直接返回 瀏覽器使用本地緩存

#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
   return -1;
}
複製代碼
  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()過程總結:

  1. 執行過程調用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;
    }
複製代碼
  1. 包裝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的調用過程算分析完了

springMVC思惟導圖

相關文章
相關標籤/搜索