SpringMVC源码分析(三)

15 篇文章 0 订阅
3 篇文章 0 订阅

SpringMvc源码分析

第九章 Spring Aop 源码解析(二)


前言

这一章开始,我们来学习一下SpringMvc框架的源码

一、测试环境

controller:

@Controller
@RequestMapping("/demo")
public class DemoController  {
    @RequestMapping("/handle01")
    public String handle01(String name,Map<String,Object> model) {
		System.out.println("++++++++handler业务逻辑处理中....");
        Date date = new Date();
        model.put("date",date);
        return "success";
    }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>hi,boy</title>
  </head>
  <body>
    <a href="/demo/handle01?name=zhangsan">点我测试</a>
  </body>
</html>

success.jsp

<%@ page language="java" isELIgnored="false" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>Insert title here</title>
 </head>
 <body>
        <%System.out.println("跳转到页面");%>
        跳转成功!服务器时间:${date}
 </body>
 </html>

一个简单的测试环境搭建完成

二、SpringMvc九大组件

/** MultipartResolver used by this servlet. */
@Nullable
private MultipartResolver multipartResolver;

/** LocaleResolver used by this servlet. */
@Nullable
private LocaleResolver localeResolver;

/** ThemeResolver used by this servlet. */
@Nullable
private ThemeResolver themeResolver;

/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;

/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters;

/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;

/** RequestToViewNameTranslator used by this servlet. */
@Nullable
private RequestToViewNameTranslator viewNameTranslator;

/** FlashMapManager used by this servlet. */
@Nullable
private FlashMapManager flashMapManager;

/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;

三、SpringMvc九大组件初始化

DispatcherServlet中的onRefresh(),该⽅法中初始化了九⼤组件

/**
 * This implementation calls {@link #initStrategies}.
 */
@Override
protected void onRefresh(ApplicationContext context) {
	// 初始化策略
	initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 * 初始化策略
 */
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(context);方法:

private void initHandlerMappings(ApplicationContext context) {
	this.handlerMappings = null;
	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 {
		try {
			// 否则在ioc中按照固定名称去找
			HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
			this.handlerMappings = Collections.singletonList(hm);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Ignore, we'll add a default HandlerMapping later.
		}
	}

	// 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);
		if (logger.isTraceEnabled()) {
			logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
					"': using default strategies from DispatcherServlet.properties");
		}
	}
}

需要注意的时detectAllHandlerMappings可以在web.xml中进行配置true或者false;默认的是true;主要用于判断是根据类型在ioc容器中查找还是根据id为handlerMapping进行查找;如果没找到就按照默认的策略生成handlerMapping


/**
 * Name of the class path resource (relative to the DispatcherServlet class)
 * that defines DispatcherServlet's default strategy names.
 */
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

private static final Properties defaultStrategies;

static {
	// Load default strategy implementations from properties file.
	// This is currently strictly internal and not meant to be customized
	// by application developers.
	try {
		ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
		defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
	}
	catch (IOException ex) {
		throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
	}
}

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
	String key = strategyInterface.getName();
	// 查找属性文件
	String value = defaultStrategies.getProperty(key);
	if (value != null) {
		String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
		List<T> strategies = new ArrayList<>(classNames.length);
		for (String className : classNames) {
			try {
				Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
				Object strategy = createDefaultStrategy(context, clazz);
				strategies.add((T) strategy);
			}
			catch (ClassNotFoundException ex) {
				throw new BeanInitializationException(
						"Could not find DispatcherServlet's default strategy class [" + className +
						"] for interface [" + key + "]", ex);
			}
			catch (LinkageError err) {
				throw new BeanInitializationException(
						"Unresolvable class definition for DispatcherServlet's default strategy class [" +
						className + "] for interface [" + key + "]", err);
			}
		}
		return strategies;
	}
	else {
		return new LinkedList<>();
	}
}

DispatcherServlet.properties资源文件定义了一些默认的内容:

# 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

四、DispatcherServlet 分析

在这里插入图片描述
这是DispatcherServlet 的类图,通过源码分析,我们可以看的到,真正处理请求的地方在FrameworkServlet类中;

	/**
	 * Delegate GET requests to processRequest/doService.
	 * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
	 * with a {@code NoBodyResponse} that just captures the content length.
	 * @see #doService
	 * @see #doHead
	 */
	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate POST requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

doGetdoPost均调用了processRequest方法:

/**
 * Process this request, publishing an event regardless of the outcome.
 * <p>The actual event handling is performed by the abstract
 * {@link #doService} template method.
 */
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	long startTime = System.currentTimeMillis();
	Throwable failureCause = null;

	// 获取上一个请求保存的LocaleContext
	LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
	// 建立新的LocaleContext
	LocaleContext localeContext = buildLocaleContext(request);

	// 获取上一个请求保存的RequestAttributes
	RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
	// 建立新的RequestAttributes
	ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
	//异步管理器
	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
	asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

	// 新的RequestAttributes设置进LocalThread
	initContextHolders(request, localeContext, requestAttributes);

	try {
		doService(request, response);
	}
	catch (ServletException | IOException ex) {
		failureCause = ex;
		throw ex;
	}
	catch (Throwable ex) {
		failureCause = ex;
		throw new NestedServletException("Request processing failed", ex);
	}

	finally {
		resetContextHolders(request, previousLocaleContext, previousAttributes);
		if (requestAttributes != null) {
			requestAttributes.requestCompleted();
		}
		logResult(request, response, failureCause, asyncManager);
		publishRequestHandledEvent(request, response, startTime, failureCause);
	}
}

很明显,处理逻辑在doService方法中;

FrameworkServlet.java
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)throws Exception;

DispatcherServlet#doService.java
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	logRequest(request);

	// Keep a snapshot of the request attributes in case of an include,
	// to be able to restore the original attributes after the include.
	Map<String, Object> attributesSnapshot = null;
	if (WebUtils.isIncludeRequest(request)) {
		attributesSnapshot = new HashMap<>();
		Enumeration<?> attrNames = request.getAttributeNames();
		while (attrNames.hasMoreElements()) {
			String attrName = (String) attrNames.nextElement();
			if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
				attributesSnapshot.put(attrName, request.getAttribute(attrName));
			}
		}
	}

	// Make framework objects available to handlers and view objects.
	request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
	request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
	request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
	request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
	//管理重定向参数属性
	if (this.flashMapManager != null) {
		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
		if (inputFlashMap != null) {
			request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
		}
		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
		request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
	}

	try {
		doDispatch(request, response);
	}
	finally {
		if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Restore the original attribute snapshot, in case of an include.
			if (attributesSnapshot != null) {
				restoreAttributesAfterInclude(request, attributesSnapshot);
			}
		}
	}
}

进入doDispatch(request, response);方法;

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 请求头
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// 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)调用getHandler()获取到能够处理当前请求的执⾏HandlerExecutionChain(Handler+拦截器)
2)调用getHandlerAdapter();获取能够执行1)中Handler的适配器
3)适配器调用Handler执行ha.handle(总会返回⼀个ModelAndView对象)
4)调用processDispatchResult()方法完成视图渲染跳转

接下来来看下mappedHandler = getHandler(processedRequest);

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

通过调试模式,我们可以看到:
在这里插入图片描述
存在两个HandlerMapping ,第一个BeanNameUrlHandlerMappingspring早期使用的一种配置方式,本次源码分析均使用注解方式进行,所以我们主要使用的是第二个RequestMappingHandlerMapping,继续进行,ok 可以看到return handler;
回到doDispatch方法,我们继续看下getHandlerAdapter(mappedHandler.getHandler());这个方法:

/**
 * Return the HandlerAdapter for this handler object.
 * @param handler the handler object to find an adapter for
 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	if (this.handlerAdapters != null) {
		// 是否支持当前的handler
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(handler)) {
				return adapter;
			}
		}
	}
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

同样的,存在三个HandlerAdapter,本次主要使用的是最后一个在这里插入图片描述
最后return adapter;
回到doDispatch方法,我们继续看下ha.handle(processedRequest, response, mappedHandler.getHandler());这个方法,来看下具体的执行细节:

HandlerAdapter.java
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

AbstractHandlerMethodAdapter.java
/**
 * This implementation expects the handler to be an {@link HandlerMethod}.
 */
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {

	return handleInternal(request, response, (HandlerMethod) handler);
}

RequestMappingHandlerAdapter.java
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	checkRequest(request);

	// Execute invokeHandlerMethod in synchronized block if required.
	// 判断当前是否需要支持在同一个session中只能线性地处理请求
	if (this.synchronizeOnSession) {
		// 获取当前请求的session对象
		HttpSession session = request.getSession(false);
		if (session != null) {
			// 为当前session生成一个唯一的可以用于锁定的key
			Object mutex = WebUtils.getSessionMutex(session);
			synchronized (mutex) {
				// 对HandlerMethod进行参数等的适配处理,并调用目标handler
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No HttpSession available -> no mutex necessary
			// 如果当前不存在session,则直接对HandlerMethod进行适配
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
	}
	else {
		// No synchronization on session demanded at all...
		// 如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}

	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			prepareResponse(response);
		}
	}

	return mav;
}

点击进入invokeHandlerMethod(request, response, handlerMethod);方法:

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {
		// 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中配置的InitBinder,用于进行参数的绑定
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		// 获取容器中全局配置的ModelAttribute和当前当前HandlerMethod所对应的Controller中配置的ModelAttribute,这些配置的方法将会在目标方法调用之前进行调用
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

		// 将handlerMethod封装为一个ServletInvocableHandlerMethod对象
		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		if (this.argumentResolvers != null) {
			// 设置当前容器中配置的所有ArgumentResolver 参数解析器
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		if (this.returnValueHandlers != null) {
			// 设置当前容器中配置的所有ReturnValueHandler 返回值解析器
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		// 将前面创建的WebDataBinderFactory设置到ServletInvocableHandlerMethod中
		invocableMethod.setDataBinderFactory(binderFactory);

		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		// 这里initModel()方法主要作用是调用前面获取到的@ModelAttribute标注的方法,
		// 从而达到@ModelAttribute标注的方法能够在目标Handler调用之前调用的目的
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.setTaskExecutor(this.taskExecutor);
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors);
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		if (asyncManager.hasConcurrentResult()) {
			Object result = asyncManager.getConcurrentResult();
			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
			asyncManager.clearConcurrentResult();
			LogFormatUtils.traceDebug(logger, traceOn -> {
				String formatted = LogFormatUtils.formatValue(result, !traceOn);
				return "Resume with async result [" + formatted + "]";
			});
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}

		// 对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}

		// 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,
		// 还会判断是否需要将FlashAttributes封装到新的请求中
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
		webRequest.requestCompleted();
	}
}

继续进入invokeAndHandle方法:

/**
 * Invoke the method and handle the return value through one of the
 * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
 * @param webRequest the current request
 * @param mavContainer the ModelAndViewContainer for this request
 * @param providedArgs "given" arguments matched by type (not resolved)
 */
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	// 对目标handler的参数进行处理,并且调用目标handler
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	// 设置相关的返回状态
	setResponseStatus(webRequest);

	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			disableContentCachingIfNecessary(webRequest);
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}

	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
	try {
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}

继续进入invokeForRequest(webRequest, mavContainer, providedArgs);

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	// 将request中的参数转换为当前handler的参数形式
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
	if (logger.isTraceEnabled()) {
		logger.trace("Arguments: " + Arrays.toString(args));
	}
	// 这里doInvoke()方法主要是结合处理后的参数,使用反射对目标方法进行调用
	return doInvoke(args);
}

Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); 这段代码封装了我们访问时的参数数组,我们来看一下:

/**
 * Get the method argument values for the current request, checking the provided
 * argument values and falling back to the configured argument resolvers.
 * <p>The resulting array will be passed into {@link #doInvoke}.
 * @since 5.1.2
 * 本方法主要是通过当前容器中配置的ArgumentResolver对request中的参数进行转化,
 * 将其处理为目标handler的参数的形式
 */
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	// 获取当前handler所声明的所有参数,主要包括参数名,参数类型,参数位置,所标注的注解等等属性
	MethodParameter[] parameters = getMethodParameters();
	if (ObjectUtils.isEmpty(parameters)) {
		return EMPTY_ARGS;
	}

	Object[] args = new Object[parameters.length];
	for (int i = 0; i < parameters.length; i++) {
		MethodParameter parameter = parameters[i];
		parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
		// providedArgs是调用方提供的参数,这里主要是判断这些参数中是否有当前类型,如果有,则直接使用调用方提供的参数,对于请求处理而言,默认情况下,
		// 调用方提供的参数都是长度为0的数组
		args[i] = findProvidedArgument(parameter, providedArgs);
		if (args[i] != null) {
			continue;
		}
		// 如果在调用方提供的参数中不能找到当前类型的参数值,则遍历Spring容器中所有的
		// ArgumentResolver,判断哪种类型的Resolver支持对当前参数的解析,这里的判断
		// 方式比较简单,比如RequestParamMethodArgumentResolver就是判断当前参数
		// 是否使用@RequestParam注解进行了标注
		if (!this.resolvers.supportsParameter(parameter)) {
			throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
		}
		try {
			// 如果能够找到对当前参数进行处理的ArgumentResolver,则调用其
			// resolveArgument()方法从request中获取对应的参数值,并且进行转换
			args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
		}
		catch (Exception ex) {
			// Leave stack trace for later, exception may actually be resolved and handled...
			if (logger.isDebugEnabled()) {
				String exMsg = ex.getMessage();
				if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
					logger.debug(formatArgumentError(parameter, exMsg));
				}
			}
			throw ex;
		}
	}
	return args;
}

这个方法主要是对于参数的一些封装,我们回到invokeForRequest方法,继续执行,点击进入doInvoke方法来了解下是如何反射调用对应方法的:

/**
 * Invoke the handler method with the given argument values.
 */
@Nullable
protected Object doInvoke(Object... args) throws Exception {
	ReflectionUtils.makeAccessible(getBridgedMethod());
	try {
		return getBridgedMethod().invoke(getBean(), args);
	}
	catch (IllegalArgumentException ex) {
		assertTargetBean(getBridgedMethod(), getBean(), args);
		String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
		throw new IllegalStateException(formatInvokeError(text, args), ex);
	}
	catch (InvocationTargetException ex) {
		// Unwrap for HandlerExceptionResolvers ...
		Throwable targetException = ex.getTargetException();
		if (targetException instanceof RuntimeException) {
			throw (RuntimeException) targetException;
		}
		else if (targetException instanceof Error) {
			throw (Error) targetException;
		}
		else if (targetException instanceof Exception) {
			throw (Exception) targetException;
		}
		else {
			throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
		}
	}
}

ok,到这里我们能发现return getBridgedMethod().invoke(getBean(), args);执行了一个invoke,到此handler方法执行完毕

五、视图渲染细节分析

了解了具体的handler调用、适配器处理、参数封装以及执行返回modelAndView对象,我们接下来来了解下具体的视图渲染执行流程:
回到org.springframework.web.servlet.DispatcherServlet#doDispatch方法,找到processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);点击进入:

/**
 * Handle the result of handler selection and handler invocation, which is
 * either a ModelAndView or an Exception to be resolved to a ModelAndView.
 */
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
		@Nullable Exception exception) throws Exception {

	boolean errorView = false;
    //判断异常
	if (exception != null) {
		if (exception instanceof ModelAndViewDefiningException) {
			logger.debug("ModelAndViewDefiningException encountered", exception);
			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
		}
		else {
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			mv = processHandlerException(request, response, handler, exception);
			errorView = (mv != null);
		}
	}

	// Did the handler return a view to render?
	if (mv != null && !mv.wasCleared()) {
		render(mv, request, response);
		if (errorView) {
			WebUtils.clearErrorRequestAttributes(request);
		}
	}
	else {
		if (logger.isTraceEnabled()) {
			logger.trace("No view rendering, null ModelAndView returned.");
		}
	}

	if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
		// Concurrent handling started during a forward
		return;
	}

	if (mappedHandler != null) {
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}

进入render(mv, request, response);方法:

/**
 * Render the given ModelAndView.
 * <p>This is the last stage in handling a request. It may involve resolving the view by name.
 * @param mv the ModelAndView to render
 * @param request current HTTP servlet request
 * @param response current HTTP servlet response
 * @throws ServletException if view is missing or cannot be resolved
 * @throws Exception if there's a problem rendering the view
 */
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	// Determine locale for request and apply it to the response.
	Locale locale =
			(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
	response.setLocale(locale);

	View view;
	String viewName = mv.getViewName();
	if (viewName != null) {
		// We need to resolve the view name.
		view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
		if (view == null) {
			throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
					"' in servlet with name '" + getServletName() + "'");
		}
	}
	else {
		// No need to lookup: the ModelAndView object contains the actual View object.
		view = mv.getView();
		if (view == null) {
			throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
					"View object in servlet with name '" + getServletName() + "'");
		}
	}

	// Delegate to the View object for rendering.
	if (logger.isTraceEnabled()) {
		logger.trace("Rendering view [" + view + "] ");
	}
	try {
		if (mv.getStatus() != null) {
			response.setStatus(mv.getStatus().value());
		}
		view.render(mv.getModelInternal(), request, response);
	}
	catch (Exception ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Error rendering view [" + view + "]", ex);
		}
		throw ex;
	}
}

进入view.render(mv.getModelInternal(), request, response);方法:

/**
 * Prepares the view given the specified model, merging it with static
 * attributes and a RequestContext attribute, if necessary.
 * Delegates to renderMergedOutputModel for the actual rendering.
 * @see #renderMergedOutputModel
 */
@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
		HttpServletResponse response) throws Exception {

	if (logger.isDebugEnabled()) {
		logger.debug("View " + formatViewName() +
				", model " + (model != null ? model : Collections.emptyMap()) +
				(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
	}
	
	Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
	// 准备响应
	prepareResponse(request, response);
	// 渲染视图
	renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}

进入renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);方法:

/**
 * Render the internal resource given the specified model.
 * This includes setting the model as request attributes.
 */
@Override
protected void renderMergedOutputModel(
		Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

	// 将模型中的一些属性暴露成RequestAttributes
	exposeModelAsRequestAttributes(model, request);

	// Expose helpers as request attributes, if any.
	exposeHelpers(request);

	// 物理视图路径
	String dispatcherPath = prepareForRendering(request, response);

	// 请求分发的对象
	RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
	if (rd == null) {
		throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
				"]: Check that the corresponding file exists within your web application archive!");
	}

	// If already included or response already committed, perform include, else forward.
	if (useInclude(request, response)) {
		response.setContentType(getContentType());
		if (logger.isDebugEnabled()) {
			logger.debug("Including [" + getUrl() + "]");
		}
		rd.include(request, response);
	}

	else {
		// Note: The forwarded resource is supposed to determine the content type itself.
		if (logger.isDebugEnabled()) {
			logger.debug("Forwarding to [" + getUrl() + "]");
		}
		rd.forward(request, response);
	}
}


/**
 *  request.setAttribute(name, value); 这就是为什么jsp中可以从请求域能将数据取出来的原因
 */
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
		HttpServletRequest request) throws Exception {

	model.forEach((name, value) -> {
		if (value != null) {
			request.setAttribute(name, value);
		}
		else {
			request.removeAttribute(name);
		}
	});
}

到这里 rd.forward(request, response);就完成了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值