Spring MVC 是什么

SpringMVC 全名叫 Spring Web MVC,是⼀种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级Web 框架 。

SpringMvc开发web是非常方便的,那么它在背后做了什么工作呢?为什么咱们传统的servlet开发,几乎在spring中屏蔽了,只需要配置@Controller、@RequestMapping这些注解就能做业务逻辑开发呢?对于源码的阅读能让咱们理解这些方法。

DispatcherServlet源码阅读

要使用springmvc,必须要在web.xml中配置DispatcherServlet请求分发

<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:springmvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

先看看DispatcherServlet的类图结构,DispatcherServlet也是一个特殊的Servlet,它接管了请求,然后对每个请求进行分发处理。

DispatcherServlet

spring九大组件的初始化

因为DispatcherServlet的分发需要使用到九大组件,所以咱了解下这些组件时怎么初始化的。

众所周知,Servlet的生命周期分别为:init(),service(),destory()三个阶段。DispatcherServlet的init方法在

org.springframework.web.servlet.HttpServletBean#init()中

public final void init() throws ServletException {
		// 核心调用方法
		initServletBean();
	}

然后调用org.springframework.web.servlet.FrameworkServlet#initServletBean()方法进行webApplicationContext的初始化

protected final void initServletBean() throws ServletException {

		try {
            // 初始化initWebApplicationContext
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}

	}

当初始化完成后,会执行org.springframework.context.support.AbstractApplicationContext#finishRefresh()方法,触发刷新事件,最终调用到DispatcherServlet#onRefresh方法

// 初始化策略
initStrategies(context);

即初始化SpringMvc的九大组件

protected void initStrategies(ApplicationContext context) {
		// 多文件上传的组件
		initMultipartResolver(context);
		// 初始化本地语言环境
		initLocaleResolver(context);
		// 初始化模板处理器
		initThemeResolver(context);
		// 初始化HandlerMapping
		initHandlerMappings(context);
		// 初始化参数适配器
		initHandlerAdapters(context);
		// 初始化异常拦截器
		initHandlerExceptionResolvers(context);
		// 初始化视图预处理器
		initRequestToViewNameTranslator(context);
		// 初始化视图转换器
		initViewResolvers(context);
		// 初始化 FlashMap 管理器
		initFlashMapManager(context);
	}

着重关注下initHandlerMappings进行HandlerMapping的初始化

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    // 检测所有的handlerMapping还是只需要“handlerMapping”bean
    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        // 找到所有的HandlerMapping
        Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        // 否则在ioc中按照固定名称去找
        HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
        this.handlerMappings = Collections.singletonList(hm);
    }

    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    if (this.handlerMappings == null) {
        // 最后还为空则按照默认策略生成
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    }
}

看看默认策略怎么生成的

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    // 从DispatcherServlet.properties加载defaultStrategies
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList<>(classNames.length);
        for (String className : classNames) {
            Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
            Object strategy = createDefaultStrategy(context, clazz);
            strategies.add((T) strategy);
        }
        return strategies;
    }
    else {
        return new LinkedList<>();
    }
}

看看DispatcherServlet.properties中配置,HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;配置了2个默认的HandlerMapping

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

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

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

spring的分发处理流程

看看doDispatch方法源码

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				// 1 检查是否是文件上传的请求
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				/*
				 	2 取得处理当前请求的Controller,这里也称为Handler,即处理器
				 	  这里并不是直接返回 Controller,而是返回 HandlerExecutionChain 请求处理链对象
				 	  该对象封装了Handler和Inteceptor
				 */
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					// 如果 handler 为空,则返回404
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				// 3 获取处理请求的处理器适配器 HandlerAdapter
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				// 处理 last-modified 请求头省略代码........
				

				// Actually invoke the handler.
				// 4 实际处理器处理请求,返回结果视图对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 结果视图对象的处理
				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			// 触发异常捕获或者拦截器的执行完成事件执行
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			//最终会调用HandlerInterceptor的afterCompletion 方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			//最终会调用HandlerInterceptor的afterCompletion 方法
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

可以看到doDispatch分发流程为:

  1. 检查是否是文件上传的请求

  2. 取得处理当前请求的Controller,这里也称为Handler,即处理器

    这里并不是直接返回 Controller,而是返回 HandlerExecutionChain 请求处理链对象

    该对象封装了Handler和Inteceptor

    image-20201207003350985

  3. 获取处理请求的处理器适配器 HandlerAdapter

    image-20201207003403600

    对于HandlerMthod类型的handler对应的HandlerAdapter是RequestMappingHandlerAdapter,它继承于AbstractHandlerMethodAdapter,可从supports方法中看到它支持HandlerMethod类型的handler

@Override
	public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}
  1. 实际处理器处理请求,返回结果视图对象

    入口:

    image-20201207003943843

    image-20201207004010448

    进入RequestMappingHandlerAdapter#invokeHandlerMethod方法后

    image-20201207004024023

    进入ServletInvocableHandlerMethod#invokeAndHandle方法后

    进入InvocableHandlerMethod#invokeForRequest方法后

    image-20201207004034163

    进入InvocableHandlerMethod#doInvoke方法后,调用method进行处理。

    protected Object doInvoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(getBridgedMethod());
        try {
            return getBridgedMethod().invoke(getBean(), args);
        }catch (Exception ex) {
            // 省略异常处理
        }
    }
  2. 结果视图对象的处理

  3. 最终会调用HandlerInterceptor的afterCompletion 方法。

HandlerMethod的注册流程

每一个Controller类下的方法,只要含有springmvc的@RequestMapping注解,就会被当作一个handlerMethod注册到MappingRegistry中。

先看看RequestMappingHandlerMapping的类关系图

RequestMappingHandlerMapping

  1. 创建RequestMappingHandlerMapping对象的时候会执行afterPropertiesSet方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#afterPropertiesSet()
  2. 然后调用父类org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods()
  3. 再调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods(Object handler)方法
protected void detectHandlerMethods(Object handler) {
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

		if (handlerType != null) {
			Class<?> userType = ClassUtils.getUserClass(handlerType);
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
							// 拿到符合映射关系的method,比如包含有RequestMapping注解等,并返回RequestMappingInfo
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							// ...........
						}
					});
			methods.forEach((method, mapping) -> {
				// 查找到最终的执行方法,有可能存在父类或接口中,并检查方法是否合法
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				// 注册到mappingRegistry中
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}
  1. 最后看看org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register方法
// registry注册容器Map
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
// 注册方法
public void register(T mapping, Object handler, Method method) {
    this.readWriteLock.writeLock().lock();
    try {
        // 从BeanFactory中获取得到method对应的Spring Bean对象,封装到HandlerMethod对象
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        // 校验是否唯一
        assertUniqueMethodMapping(handlerMethod, mapping);
        this.mappingLookup.put(mapping, handlerMethod);

        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            this.urlLookup.add(url, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }

        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }
        // 添加到registry Map中
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        // 释放锁
        this.readWriteLock.writeLock().unlock();
    }
}

// 从BeanFactory中获取得到method对应的Spring Bean对象,封装到HandlerMethod对象
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
		HandlerMethod handlerMethod;
		if (handler instanceof String) {
			String beanName = (String) handler;
			handlerMethod = new HandlerMethod(beanName,
					obtainApplicationContext().getAutowireCapableBeanFactory(), method);
		}
		else {
			handlerMethod = new HandlerMethod(handler, method);
		}
		return handlerMethod;
	}