SpringMVC源码分析系列(精简)

SpringMVC源码分析系列:

启动过程

常见以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
复制代码

《SpringMVC源码分析系列(精简)》

可以看到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解析器做了什么

解析过程较为复杂 通过注释我们可以得知以下对象将被装载

《SpringMVC源码分析系列(精简)》

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);
	}
	...
}
复制代码

过程概括:

  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为例 我们先看下他的继承关系

《SpringMVC源码分析系列(精简)》

可以看到有个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为例来讲,先看下继承关系

《SpringMVC源码分析系列(精简)》

同样看到了实现了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默认解析器

《SpringMVC源码分析系列(精简)》

看一下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思维导图

    原文作者:PackageManagerService
    原文地址: https://juejin.im/post/5aaf4c556fb9a028b547af83
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞