SpringMVC源码总结

目录

1.什么是SpringMVC

2.由问题引出SpringMVC两大配置

3.SpringMVC流程解析

1.大致流程

2.剖析 getHandler(processedRequest)

3.剖析getHandlerAdapter(mappedHandler.getHandler())

4.剖析mappedHandler.applyPreHandle(processedRequest, response) 

5.剖析mv = ha.handle(processedRequest, response, mappedHandler.getHandler())

6. 剖析mappedHandler.applyPostHandle(processedRequest, response, mv)

7.剖析processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

4.SpringMVC的9大组件

5.mvc:annotation-driven 标签

1.没有配置和的情况下

2.只加

3.加和

6.拦截器

7.异常解析器


1.什么是SpringMVC

是由Spring来实现web模块,简化web开发

MVC:Model + View + Controller,Model封装数据,View界面显示,Controller控制整个项目的跳转。MVC的优势在于,整个项目进行解耦,每层只写自己的东西,不写其他业务逻辑的代码。后期维护更加方便,扩展性更高

但是SpringMVC和传统MVC架构是有区别的,区别在于下图,多了一个前端控制器,由前端控制器来进行智能的派发,而不再是请求直接指定到对应的Controller。

 

2.由问题引出SpringMVC两大配置

/拦截所有请求,但是不拦截jsp页面

/*,拦截所有请求,包括jsp页面

当我们使用“/*”拦截时,jsp请求也会来到springmvc,但是我们没办法处理,所以只能使用“/”来拦截

当我们请求静态资源时,无论配置哪一个,都会被SpringMVC拦截,那么我们究竟应该怎么配置呢

我们可以看到tomcat中的父web.xml中的default servlet

由上图可见,servlet是用于拦截静态资源的(除jsp和servlet)。当我们配置了前端控制器拦截了“/”,就相当于禁用掉了tomcat的default servlet。这样当静态资源请求来到DispatcherServlet(前端控制器)看哪个方法能的requestMapping是能够处理的。

但是我们没有一个是能处理的,所以就会404。解决步骤第五节

3.SpringMVC流程解析

首先查看org.springframework.web.servlet.DispatcherServlet是什么

 

可以看出来它是一个Servlet,既然是Servlet。那么肯定是要调用doGet(),doPost()。看看是在哪儿调用的

protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

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

		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);

		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

		initContextHolders(request, localeContext, requestAttributes);

		try {
            //进入此方法
			doService(request, response);
		}
		catch (ServletException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (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();
			}

			if (logger.isDebugEnabled()) {
				if (failureCause != null) {
					this.logger.debug("Could not complete request", failureCause);
				}
				else {
					if (asyncManager.isConcurrentHandlingStarted()) {
						logger.debug("Leaving response open for concurrent processing");
					}
					else {
						this.logger.debug("Successfully completed request");
					}
				}
			}

			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + getRequestUri(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<String, Object>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
					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());

		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 {
            //终于来到了SpringMVC的核心代码
			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);
				}
			}
		}
	}

 

1.大致流程

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);

				//2.决定我们当前请求,找到哪个类能来处理这个请求。得到处理器执行链(目标方法与拦截器)
				mappedHandler = getHandler(processedRequest);
                //如果没有找到能来处理这个请求的处理器。那么就抛出异常404
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				//3.拿到能执行这个类的所有方法的适配器,后续会利用适配器来执行目标方法(AnnotationMethodHandlerAdapter)
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				//4.获取请求方式
				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;
					}
				}
                //5.运行拦截器的preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				//6.真正的执行目标方法,利用适配器执行.将目标方法执行完成后的返回值作为视图名,
                //设置保存到ModelAndView中,所以无论目标方法返回值是何种类型,最终都会返回这个
                //ModelAndView
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
                //如果没有视图名(方法返回值为void),默认设置一个视图名
				applyDefaultViewName(processedRequest, mv);
                //7.执行拦截器的postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
                //当执行目标方法出现异常时,会将异常对象赋值给dispatchException
				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);
			}
            //6.根据方法最终执行完成后封装的ModelAndView,转发到对应页面,而且ModelAndView中的数
            //据可以从请求域中获取
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
        //上述代码出现任何异常都会走到这里
		catch (Exception ex) {
            //执行拦截器的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			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);
				}
			}
		}
	}

1.请求来到doDispatch()方法

2.判断是否是文件上传请求,如果是就将请求包装

3.决定我们当前请求,找到哪个类能来处理这个请求。

4.拿到能执行这个类的所有方法的适配器,后续会利用适配器来执行目标方法

5.真正的执行目标方法,利用适配器执行.将目标方法执行完成后的返回值作为视图名,设置保存到ModelAndView中,所以无论目标方法返回值是何种类型,最终都会返回这个ModelAndView

6.根据方法最终执行完成后封装的ModelAndView,转发到对应页面,而且ModelAndView中的数据封装到请求域中。

上述六步就是SpringMVC处理请求的大致流程,细节部分见下方。

2.剖析 getHandler(processedRequest)

那么是如何根据请求就能找到对应的处理器类呢?请看下方

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //this.handlerMappings中有一个DefaultAnnotationHandlerMapping
        //它里面有一个属性为HandlerMap保存了所有的方法与处理器映射关系,key为方法名,value为controller对象。
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
            //找到了能处理该请求的处理器并返回,该处理器封装了拦截器链,controller对象等
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

3.剖析getHandlerAdapter(mappedHandler.getHandler())

如何根据处理器获得适配器呢?请看下方

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        //this.handlerAdapters中有一个AnnotationMethodHandlerAdapter。我们注解模式就是使用
        //它。直接返回AnnotationMethodHandlerAdapter
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
			if (ha.supports(handler)) {
				return ha;
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

4.剖析mappedHandler.applyPreHandle(processedRequest, response) 

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获取所有拦截器
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
            //遍历拦截器
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
                //调用拦截器的preHandle方法。当拦截器返回false的时候,直接执行
                //AfterCompletion方法后直接返回,不再执行后续流程
                //当返回true的时候,遍历执行所有拦截器的preHandle方法。
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
                //记录一下索引
				this.interceptorIndex = i;
			}
		}
		return true;
	}

 

5.剖析mv = ha.handle(processedRequest, response, mappedHandler.getHandler())

在这一步真正通过适配器执行了目标方法。SpringMVC如何确定每一个参数的值。

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
        //拿到处理器的类型
		Class<?> clazz = ClassUtils.getUserClass(handler);
        //判断当前类是否标记@SessionAttributes注解
		Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
		if (annotatedWithSessionAttributes == null) {
			annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
			this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
		}

		if (annotatedWithSessionAttributes) {
			checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
		}
		else {
			checkAndPrepare(request, response, true);
		}

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return invokeHandlerMethod(request, response, handler);
				}
			}
		}
        //执行此方法
		return invokeHandlerMethod(request, response, handler);
	}

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
        //获取方法解析器。用解析器得到当前方法的注解等
		ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
        //根据解析器得到哪个方法能够执行
		Method handlerMethod = methodResolver.resolveHandlerMethod(request);
        //获得方法执行器
		ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
        //包装原生的reuqest,response
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
        //创建一个BindingAwareModelMap。这就是隐含模型
		ExtendedModelMap implicitModel = new BindingAwareModelMap();
        //重点:执行目标方法
		Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
		ModelAndView mav =
				methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
		methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
		return mav;
	}
//真正执行目标方法,目标方法利用反射执行期间确定参数值,提前执行modelattribute等所有操作都在这个//方法中。第一个参数为目标方法,第二个参数为目标处理器,第三个参数为隐含模型
public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

		Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
		try {
			boolean debug = logger.isDebugEnabled();
        //@SessionAttributes注解中标注的属性,放入session中。同时给隐含模型中放入
			for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
				Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
				if (attrValue != null) {
					implicitModel.addAttribute(attrName, attrValue);
				}
			}
        //获取到所有标注了@ModelAttribut注解的方法
			for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
				Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
                //先确定@ModelAttribut注解的方法执行时要使用的每一个参数的值,进去看看
				Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
				if (debug) {
					logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
				}
                //获得@ModelAttribut注解的方法的value值
				String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
				if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
					continue;
				}
                //将该方法设置成可访问的
				ReflectionUtils.makeAccessible(attributeMethodToInvoke);
                //执行目标方法
				Object attrValue = attributeMethodToInvoke.invoke(handler, args);
                //如果@ModelAttribut注解的方法没有设置value值
				if ("".equals(attrName)) {
                //获得@ModelAttribut注解的方法的返回值类型
					Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
                //变量名为返回值类型首字母小写
					attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
				}
                //如果隐含模型不包含attrName
				if (!implicitModel.containsAttribute(attrName)) {
                //将此方法的返回值类型作为key,返回值作为value放入隐含模型
					implicitModel.addAttribute(attrName, attrValue);
				}
			}
            //上述就是@ModelAttribut标注的方法的提前运行
            //开始执行目标方法,首先解析目标方法的参数是哪些值
			Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
			if (debug) {
				logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
			}
			ReflectionUtils.makeAccessible(handlerMethodToInvoke);
			return handlerMethodToInvoke.invoke(handler, args);
		}
		catch (IllegalStateException ex) {
			// Internal assertion failed (e.g. invalid signature):
			// throw exception with full handler method context...
			throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
		}
		catch (InvocationTargetException ex) {
			// User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
			ReflectionUtils.rethrowException(ex.getTargetException());
			return null;
		}
	}

解析参数的值

	private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

		Class<?>[] paramTypes = handlerMethod.getParameterTypes();
        //创建一个和目标方法参数个数相同的数组
		Object[] args = new Object[paramTypes.length];
        
		for (int i = 0; i < args.length; i++) {
			MethodParameter methodParam = new SynthesizingMethodParameter(handlerMethod, i);
			methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
			GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
			String paramName = null;
			String headerName = null;
			boolean requestBodyFound = false;
			String cookieName = null;
			String pathVarName = null;
			String attrName = null;
			boolean required = false;
			String defaultValue = null;
			boolean validate = false;
			Object[] validationHints = null;
			int annotationsFound = 0;
            //获取到这个参数的所有注解
			Annotation[] paramAnns = methodParam.getParameterAnnotations();
            //找到目标方法这个参数的所有注解,如果有注解就解析并保存
			for (Annotation paramAnn : paramAnns) {
				if (RequestParam.class.isInstance(paramAnn)) {
					RequestParam requestParam = (RequestParam) paramAnn;
					paramName = requestParam.name();
					required = requestParam.required();
					defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
					annotationsFound++;
				}
				else if (RequestHeader.class.isInstance(paramAnn)) {
					RequestHeader requestHeader = (RequestHeader) paramAnn;
					headerName = requestHeader.name();
					required = requestHeader.required();
					defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
					annotationsFound++;
				}
				else if (RequestBody.class.isInstance(paramAnn)) {
					requestBodyFound = true;
					annotationsFound++;
				}
				else if (CookieValue.class.isInstance(paramAnn)) {
					CookieValue cookieValue = (CookieValue) paramAnn;
					cookieName = cookieValue.name();
					required = cookieValue.required();
					defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
					annotationsFound++;
				}
				else if (PathVariable.class.isInstance(paramAnn)) {
					PathVariable pathVar = (PathVariable) paramAnn;
					pathVarName = pathVar.value();
					annotationsFound++;
				}
                //如果参数有@ModelAttribute注解,那么@ModelAttribute注解的值就让attrName 保存
				else if (ModelAttribute.class.isInstance(paramAnn)) {
					ModelAttribute attr = (ModelAttribute) paramAnn;
					attrName = attr.value();
					annotationsFound++;
				}
				else if (Value.class.isInstance(paramAnn)) {
					defaultValue = ((Value) paramAnn).value();
				}
				else {
					Validated validatedAnn = AnnotationUtils.getAnnotation(paramAnn, Validated.class);
					if (validatedAnn != null || paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
						validate = true;
						Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(paramAnn));
						validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
					}
				}
			}
            //上述注解一个参数只能标注其中一个
			if (annotationsFound > 1) {
				throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
						"do not specify more than one such annotation on the same parameter: " + handlerMethod);
			}
            //没有找到注解的情况,解析普通参数
			if (annotationsFound == 0) {
                //解析此参数,主要是判断当前参数是否是原生API。进入看看
				Object argValue = resolveCommonArgument(methodParam, webRequest);
                //如果是原生API,则直接赋值
				if (argValue != WebArgumentResolver.UNRESOLVED) {
					args[i] = argValue;
				}
                //此参数是否有默认值,如果有则返回默认值
				else if (defaultValue != null) {
					args[i] = resolveDefaultValue(defaultValue);
				}
				else {
                //判断当前参数是否是Model或者Map类型的
					Class<?> paramType = methodParam.getParameterType();
					if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
						if (!paramType.isAssignableFrom(implicitModel.getClass())) {
							throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
									"Model or Map but is not assignable from the actual model. You may need to switch " +
									"newer MVC infrastructure classes to use this argument.");
						}
                        //将刚刚的隐含模型赋值给当前参数,所以知道为什么我们形参能够传map了吧!!
						args[i] = implicitModel;
					}
                    //再看看是否是SessionStatus
					else if (SessionStatus.class.isAssignableFrom(paramType)) {
						args[i] = this.sessionStatus;
					}
                    //再看看是否是HttpEntity
					else if (HttpEntity.class.isAssignableFrom(paramType)) {
						args[i] = resolveHttpEntityRequest(methodParam, webRequest);
					}
                    //再看看是否是Errors
					else if (Errors.class.isAssignableFrom(paramType)) {
						throw new IllegalStateException("Errors/BindingResult argument declared " +
								"without preceding model attribute. Check your handler method signature!");
					}
                    //再看看是否是简单属性(是否是八大基础类型+String)
					else if (BeanUtils.isSimpleProperty(paramType)) {
						paramName = "";
					}
                    //如果都不是那么attrName = ""。总结一下
                    //如果是自定义对象。如果这个参数标注了@ModelAttribute注解,那么attrName就是注解的值,如果
                    //没有标注@ModelAttribute注解,就是空串
					else {
						attrName = "";
					}
				}
			}
            //确定值的环节
            //如果参数名不等于null
			if (paramName != null) {
                //获取这个参数名的值,通过request.getParameterValues(paramName)获得。后续也是类似
				args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
			}
			else if (headerName != null) {
				args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
			}
			else if (requestBodyFound) {
				args[i] = resolveRequestBody(methodParam, webRequest, handler);
			}
			else if (cookieName != null) {
				args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
			}
			else if (pathVarName != null) {
				args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
			}
            //这个环节就是确定自定义类型参数的值,还要将请求中每一个参数 赋值给这个对象。
			else if (attrName != null) {
                //获取一个webDataBinder对象
				WebDataBinder binder =
						resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
				boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
				if (binder.getTarget() != null) {
                    //调用此方法就为自定义对象赋值成功
					doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
				}
				args[i] = binder.getTarget();
				if (assignBindingResult) {
					args[i + 1] = binder.getBindingResult();
					i++;
				}
				implicitModel.putAll(binder.getBindingResult().getModel());
			}
		}

		return args;
	}
protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest)
			throws Exception {
        
		if (this.customArgumentResolvers != null) {
			for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) {
				Object value = argumentResolver.resolveArgument(methodParameter, webRequest);
				if (value != WebArgumentResolver.UNRESOLVED) {
					return value;
				}
			}
		}

		//获取参数类型
		Class<?> paramType = methodParameter.getParameterType();
        //解析标准参数(是否是原生API),进入
		Object value = resolveStandardArgument(paramType, webRequest);
		if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
			throw new IllegalStateException("Standard argument type [" + paramType.getName() +
					"] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) +
					"]. Consider declaring the argument type in a less specific fashion.");
		}
        //如果是原生API,则返回
		return value;
	}
//确定当前参数是否是原生API
protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
            //判断此参数是不是ServletRequest
			if (ServletRequest.class.isAssignableFrom(parameterType) ||
					MultipartRequest.class.isAssignableFrom(parameterType)) {
				Object nativeRequest = webRequest.getNativeRequest(parameterType);
				if (nativeRequest == null) {
					throw new IllegalStateException(
							"Current request is not of type [" + parameterType.getName() + "]: " + request);
				}
				return nativeRequest;
			}
            //判断此参数是不是ServletResponse
			else if (ServletResponse.class.isAssignableFrom(parameterType)) {
				this.responseArgumentUsed = true;
				Object nativeResponse = webRequest.getNativeResponse(parameterType);
				if (nativeResponse == null) {
					throw new IllegalStateException(
							"Current response is not of type [" + parameterType.getName() + "]: " + response);
				}
				return nativeResponse;
			}
            //判断是不是HttpSession...
			else if (HttpSession.class.isAssignableFrom(parameterType)) {
				return request.getSession();
			}
			else if (Principal.class.isAssignableFrom(parameterType)) {
				return request.getUserPrincipal();
			}
			else if (Locale.class == parameterType) {
				return RequestContextUtils.getLocale(request);
			}
			else if (InputStream.class.isAssignableFrom(parameterType)) {
				return request.getInputStream();
			}
			else if (Reader.class.isAssignableFrom(parameterType)) {
				return request.getReader();
			}
			else if (OutputStream.class.isAssignableFrom(parameterType)) {
				this.responseArgumentUsed = true;
				return response.getOutputStream();
			}
			else if (Writer.class.isAssignableFrom(parameterType)) {
				this.responseArgumentUsed = true;
				return response.getWriter();
			}
			return super.resolveStandardArgument(parameterType, webRequest);
		}

再来看看POJO是如何赋值的

首先创建一个未属性赋值的对象,并且创建一个webDataBinder对象。此对象用于绑定请求参数到自定义对象

//此环节为确定POJO的值
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
			ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {

		// Bind request parameter onto object...
		String name = attrName;
        //如果attrName是空串。
		if ("".equals(name)) {
            //就将参数类型的首字母小写作为值
			name = Conventions.getVariableNameForParameter(methodParam);
		}
		Class<?> paramType = methodParam.getParameterType();
		Object bindObject;
        //确定目标对象的值
        //如果隐含模型中有这个key(如果标记@ModelAttribute注解的方法
        //已经提前运行并且往隐含模型中放入值),那么直接从隐含模型中拿出并赋值给此参数
		if (implicitModel.containsKey(name)) {
			bindObject = implicitModel.get(name);
		}
        //看看是否是@SessionAttribute标注的参数,如果是就从session中取,如果session没有就直接抛出异常
		else if (this.methodResolver.isSessionAttribute(name, paramType)) {
			bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
			if (bindObject == null) {
				raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
			}
		}
        //如果都不是就利用反射创建我们自定义的对象
		else {
			bindObject = BeanUtils.instantiateClass(paramType);
		}
		WebDataBinder binder = createBinder(webRequest, bindObject, name);
		initBinder(handler, name, binder, webRequest);
		return binder;
	}

 看看如何绑定请求参数到自定义类型对象中

 

public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

		String name = ModelFactory.getNameForParameter(parameter);
		Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :
				createAttribute(name, parameter, binderFactory, webRequest));

		if (!mavContainer.isBindingDisabled(name)) {
			ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
			if (ann != null && !ann.binding()) {
				mavContainer.setBindingDisabled(name);
			}
		}
        //创建一个binder对象 
		WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
		if (binder.getTarget() != null) {
			if (!mavContainer.isBindingDisabled(name)) {
                //绑定请求参数到自定义对象
				bindRequestParameters(binder, webRequest);
			}
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new BindException(binder.getBindingResult());
			}
		}

		// Add resolved attribute and BindingResult at the end of the model
		Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
		mavContainer.removeAttributes(bindingResultModel);
		mavContainer.addAllAttributes(bindingResultModel);

		return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
	}

 

ConversionService 负责进行数据类型转换

Validators 进行数据校验

BindingResult 负责保存数据解析以及校验期间产生的错误

6. 剖析mappedHandler.applyPostHandle(processedRequest, response, mv)

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
        //拿到所有的拦截器
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
            //倒序遍历,逆向执行每个拦截器的postHandle方法
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}

7.剖析processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

 

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			HandlerExecutionChain mappedHandler, ModelAndView mv, 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);
			}
		}

		//当mv不是null
		if (mv != null && !mv.wasCleared()) {
            //调用render方法进行页面渲染
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
						"': assuming HandlerAdapter completed request handling");
			}
		}

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

		if (mappedHandler != null) {
            //页面渲染完成后,调用拦截器的AfterCompletion方法
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		//与国际化相关
		Locale locale = this.localeResolver.resolveLocale(request);
		response.setLocale(locale);
        //定义一个视图对象
		View view;
		if (mv.isReference()) {
			//开始使用视图解析器来通过视图名来获得视图对象,进入此方法
			view = resolveViewName(mv.getViewName(), 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.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		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 + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}

 

protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
			HttpServletRequest request) throws Exception {
        //遍历容器中的所有视图解析器。
		for (ViewResolver viewResolver : this.viewResolvers) {
            //通过视图解析器来获得view对象
			View view = viewResolver.resolveViewName(viewName, locale);
            //如果当前视图解析器能够获得view对象,那么直接返回view对象
			if (view != null) {
				return view;
			}
		}
		return null;
	}

 下面来看看视图解析器是如何得到view对象的

public View resolveViewName(String viewName, Locale locale) throws Exception {
		if (!isCache()) {
			return createView(viewName, locale);
		}
		else {
            //先从缓存中获取
			Object cacheKey = getCacheKey(viewName, locale);
			View view = this.viewAccessCache.get(cacheKey);
			if (view == null) {
				synchronized (this.viewCreationCache) {
					view = this.viewCreationCache.get(cacheKey);
					if (view == null) {
						//开始创建view,进入此方法
						view = createView(viewName, locale);
						if (view == null && this.cacheUnresolved) {
							view = UNRESOLVED_VIEW;
						}
						if (view != null) {
                            //将view放入缓存
							this.viewAccessCache.put(cacheKey, view);
							this.viewCreationCache.put(cacheKey, view);
							if (logger.isTraceEnabled()) {
								logger.trace("Cached view [" + cacheKey + "]");
							}
						}
					}
				}
			}
			return (view != UNRESOLVED_VIEW ? view : null);
		}
	}

 

protected View createView(String viewName, Locale locale) throws Exception {
		if (!canHandle(viewName, locale)) {
			return null;
		}
		//如果视图名是以"redirect:"前缀的.
		if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
			String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
            //创建一个RedirectView
			RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
			view.setHosts(getRedirectHosts());
			return applyLifecycleMethods(viewName, view);
		}
		//如果视图名是以"forward:"为前缀的.
		if (viewName.startsWith(FORWARD_URL_PREFIX)) {
			String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
            //返回InternalResourceView
			return new InternalResourceView(forwardUrl);
		}
		//如果都不是就默认创建一个view对象
		return super.createView(viewName, locale);
	}

 看上段代码可以得出总结,viewResolver(视图解析器唯一的作用就是根据视图名获得视图对象)

 下面来看看得到视图对象后是如何进行渲染的

	public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isTraceEnabled()) {
			logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
				" and static attributes " + this.staticAttributes);
		}
        //创建此map用于存放要输出的数据
		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
        //准备相应
		prepareResponse(request, response);
        //将模型数据进行渲染
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}

 

protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		//渲染数据,也就是将模型数据放入请求域中
		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 resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(request, response);
		}

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

先看看是如何渲染数据的

 

protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
		for (Map.Entry<String, Object> entry : model.entrySet()) {
			String modelName = entry.getKey();
			Object modelValue = entry.getValue();
			if (modelValue != null) {
                //将模型数据放入请求域
				request.setAttribute(modelName, modelValue);
				if (logger.isDebugEnabled()) {
					logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
							"] to request in view with name '" + getBeanName() + "'");
				}
			}
			else {
				request.removeAttribute(modelName);
				if (logger.isDebugEnabled()) {
					logger.debug("Removed model object '" + modelName +
							"' from request in view with name '" + getBeanName() + "'");
				}
			}
		}
	}

 

4.SpringMVC的9大组件

从第三步已经知道了SpringMVC的运行流程,那么问题来了,handlerMappings(处理器映射器),handlerAdapters(处理器适配器)等是什么时候完成初始化并赋值的呢?

在DispatcherServlet类中有这几个引用类型的属性(刚好是9个)。它们就是我们SpringMVC的9大组件,SpringMVC在工作的时候,关键位置都是由组件完成的。

共同点:九大组件全部都是接口,接口就是规范。我们可以实现这些接口来自定义这些组件

    //文件上传解析器
	private MultipartResolver multipartResolver;

	//区域信息解析器(很少用)
	private LocaleResolver localeResolver;

	//主题解析器(很少用)
	private ThemeResolver themeResolver;

	//Handler映射信息
	private List<HandlerMapping> handlerMappings;

	//Handler适配器
	private List<HandlerAdapter> handlerAdapters;

	//异常解析器
	private List<HandlerExceptionResolver> handlerExceptionResolvers;

	//视图名转换器,如果方法返回值是void,那么就将请求地址作为视图名(很少用)
	private RequestToViewNameTranslator viewNameTranslator;

	//允许重定向携带数据的功能,放在session中
	private FlashMapManager flashMapManager;

	//视图解析器
	private List<ViewResolver> viewResolvers;

接下来我们看到DispatcherServlet类中有一个方法,这个方法我们在Spring源码解析已经讲过了。(给子容器实现)

protected void onRefresh(ApplicationContext context) {
        //初始化9大组件
		initStrategies(context);
	}
protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}
//初始化handlerMappings
private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
        //从ioc容器中找到所有HandlerMapping类型的组件
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
                //否则从ioc容器中找一个id为handlerMapping的组件,找到了就直接赋值
				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.
			}
		}

		// 如果还是为null,就去默认策略中找,我们进入此方法
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}
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<T>(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(
							"Error loading DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]: problem with class file or dependent class", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}
static {
		//静态代码块,加载默认的策略,给九大组件赋值的步骤就在这儿了
		try {
            //从DispatcherServlet.class同级目录下找到DispatcherServlet.properties这个配置文件,9大组件从这个配置文件获取并初始化
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
		}
	}

properties文件如下

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.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
	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

上述就是9大组件的初始化。总结就是容器中找这个组件,如果没有找到就使用默认的配置。

5.mvc:annotation-driven 标签

之前我们看到SpringMVC,配置"/"后,是不拦截jsp了。jsp交给tomcat去处理了,但是静态资源还是被拦截。我们配置了<mvc:default-servlet-handler/>后,静态不拦截了,动态映射的请求又不行了。

但是当我们加上了<mvc:annotation-driven />后,动态资源,静态资源都可以访问了。这是为什么呢?

首先了解一下<mvc:default-servlet-handler/>的由来,早期的SpringMVC拦截的都是*.do,*.action等相似后缀请求。无法满足Rest风格的URL,如果将拦截请求改为"/"。那么就不管动态请求和静态请求,SpringMVC都拦截到了,但是SpringMVC是无法处理静态请求

的。所以就会404.那么SpringMVC是如何处理呢。首先在配置文件中加入<mvc:default-servlet-handler/>。它给容器中添加了一个DefaultServletHttpRequestHandler组件,用于检查什么请求SpringMVC能处理,什么请求(静态资源)不能处理。不能处理的请求转发到

WEB容器内部的Servlet来进行处理。

现在进行到了如何处理动态请求了。配置<mvc:annotation-driven />,这个配置为我们导入了哪些组件呢?

1.没有配置<mvc:default-servlet-handler/>和<mvc:annotation-driven />的情况下

在此之前我们先看看源码,没有配置<mvc:default-servlet-handler/>和<mvc:annotation-driven />的情况下

处理器映射器有两种,我们使用第二种DefaultAnnotationHandlerMapping,保存了哪些请求使用哪个处理器来处理,但是我们的handlerMap并没有保存静态资源映射的请求,所以访问静态资源会404.

再来看看处理器适配器。我们是用第三个AnnotionMethodHandlerAdapter,它来帮助我们执行目标方法。已经过时(但是思想和流程是一样的,所以说之前的源码还是有必要阅读的)

2.只加<mvc:default-servlet-handler/>

首先来看看处理器映射器,从DefaultAnnotationHandlerMapping变成了SimpleUrlHandlerMapping

所有的请求都交给DefaultServletHttpRequestHandler来处理,也就是交给tomcat处理。那么静态请求倒是ok,动态请求肯定完蛋。

再看看处理器适配器,少了一个AnnotationMethodHandlerAdapter。

3.加<mvc:default-servlet-handler/>和<mvc:annotation-driven />

先看看处理器映射器,多了一个RequestMappingHandlerMapping。保存了请求的映射信息。动态请求就能查询到了。而静态请求RequestMappingHandlerMapping没有映射,那么就使用第三个处理器映射器去让tomcat来处理

再来看看处理器适配器,我们使用第三个RequestMappingHandlerAdapter

然后利用适配器去执行目标方法。和之前的源码不同,不过思想和流程是一样的。

再来看一个接口

此接口是用于解析bean的定义信息的。用于配置文件的解析。注意AnnotationDrivenBeanDefinitionParser。看看它干了什么

代码太长就不看了,主要是解析xml标签。并且给容器中添加了很多组件。

6.拦截器

SpringMVC提供了拦截器机制。直接上源码

public interface HandlerInterceptor {

//在目标方法运行之前调用,返回布尔值类型,为true放行,为false不放行
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception;

//在目标方法运行之后执行
void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception;

//在请求整个完成之后(来到页面之后)
void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception;

}

我们只需要实现 HandlerInterceptor 接口,并重写里面的方法。后将其加入<mvc:interceptors> <bean class="org.song.interceptor.MyHandlerInterceptor"></bean> </mvc:interceptors>中即可,也可以具体拦截某些方法。

源码部分请关注3.4 3.6 3.7(最后一部分)

7.异常解析器

作为SpringMVC的九大组件之一,看看默认是加载的哪个异常解析器

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver。但是我们都不用

ResponseStatusExceptionResolver 处理标注@ResponseStatus

ExceptionHandlerExceptionResolver 处理标注了@ExceptionHandler的类

DefaultHandlerExceptionResolver 处理SpringMVC自己的异常

因为我们加了<mvc:annotation-driven />,它给我们加了ExceptionHandlerExceptionResolver。作为我们的异常解析器

解析源码,看看我们的方法出现异常SpringMVC是如何进行处理的。我们在处理器方法使用10/0试试。

我们先进入视图解析流程

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

		boolean errorView = false;
        //现在异常不为null
		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);
			}
		}

		//当mv不是null
		if (mv != null && !mv.wasCleared()) {
            //调用render方法进行页面渲染。将模型数据放入请求域,并转发到错误页面
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
						"': assuming HandlerAdapter completed request handling");
			}
		}

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

		if (mappedHandler != null) {
            //页面渲染完成后,调用拦截器的AfterCompletion方法
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception ex) throws Exception {

		//创建一个ModelAndView 
		ModelAndView exMv = null;
        //遍历异常解析器
		for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
            //尝试解析异常,
			exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
            //解析成功就返回
			if (exMv != null) {
				break;
			}
		}
		if (exMv != null) {
			if (exMv.isEmpty()) {
				request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
				return null;
			}
			// We might still need view name translation for a plain error model...
			if (!exMv.hasView()) {
				exMv.setViewName(getDefaultViewName(request));
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
			}
			WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
			return exMv;
		}
        //如果都不能处理此异常,那直接抛出去。交给tomcat处理

		throw ex;
	}

看看如何解析异常

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception ex) {

		if (shouldApplyTo(request, handler)) {
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
			}
			prepareResponse(ex, response);
            //开始解析异常
			ModelAndView result = doResolveException(request, response, handler, ex);
			if (result != null) {
				logException(ex, request);
			}
			return result;
		}
		else {
			return null;
		}
	}
protected final ModelAndView doResolveException(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

		return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
	}

 

 

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
        //首先获取到能处理这个异常的方法
		ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
		if (exceptionHandlerMethod == null) {
			return null;
		}
        //设置参数解析器。用于解析处理异常的方法的参数
		exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        //设置返回值解析器		exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
        //创建一个ModelAndViewContainer,内部其实就是一个隐含模型和视图
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();

		try {
			if (logger.isDebugEnabled()) {
				logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
			}
			Throwable cause = exception.getCause();
			if (cause != null) {
				exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
			}
			else {
				//执行目标方法
				exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
			}
		}
		catch (Throwable invocationEx) {
			// Any other than the original exception is unintended here,
			// probably an accident (e.g. failed assertion or the like).
			if (invocationEx != exception && logger.isWarnEnabled()) {
				logger.warn("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
			}
			// Continue with default processing of the original exception...
			return null;
		}

		if (mavContainer.isRequestHandled()) {
			return new ModelAndView();
		}
		else {
            //获取模型数据。可以在页面上获得
			ModelMap model = mavContainer.getModel();
			HttpStatus status = mavContainer.getStatus();
            //创建一个ModelAndView,将模型数据和视图名传进去
			ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);
			mav.setViewName(mavContainer.getViewName());
			if (!mavContainer.isViewReference()) {
				mav.setView((View) mavContainer.getView());
			}
			if (model instanceof RedirectAttributes) {
				Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
				request = webRequest.getNativeRequest(HttpServletRequest.class);
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
            //返回此ModelAndView
			return mav;
		}
	}

 

我们上述的三个异常解析器都有自己特定的使用场景

ResponseStatusExceptionResolver 处理标注@ResponseStatus的方法

ExceptionHandlerExceptionResolver 处理标注了@ExceptionHandler的方法

DefaultHandlerExceptionResolver 处理SpringMVC自己的异常

ExceptionHandlerExceptionResolver 的使用场景

//@ControllerAdvice标识这个类专门用于处理异常
@ControllerAdvice
public class MyExceptionHandler {
    //告诉SpringMVC这个方法专门处理这个类发生的异常。
    //要携带异常信息,不能给参数位置写model
    //可以直接返回ModelAndView对象
    @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
    public ModelAndView handleException01(Exception exception){
        System.out.println("来到错误页面" + exception);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("myerror");
        modelAndView.addObject("exception",exception);
        return modelAndView;
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值