SprngMVC源码学习
运行helloWorld示例进入调试界面。
DispatcherServlet:前端控制器
DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) line: 945 DispatcherServlet.doService(HttpServletRequest, HttpServletResponse) line: 876 DispatcherServlet(FrameworkServlet).processRequest(HttpServletRequest, HttpServletResponse) line: 931 DispatcherServlet(FrameworkServlet).doGet(HttpServletRequest, HttpServletResponse) line: 822 DispatcherServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 624 DispatcherServlet(FrameworkServlet).service(HttpServletRequest, HttpServletResponse) line: 807 DispatcherServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 731
由上进入源码查看
DispatcherServlet(FrameworkServlet).service(HttpServletRequest, HttpServletResponse) line: 807
的
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
...
service();
}
HttpServletBean 的实现
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {}
接下来重点关注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 { processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. //1、根据当前请求地址找到哪个处理器来处理请求 mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { //2、如果找不到报错 noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. //2\为当前请求确定适配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. //真正执行方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //处理响应结果 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
四步:
1)、所有请求进来都经过DispatcherServlet的900:doDispatch()方法(包含了处理请求以及响应的所有流程)
2)、916;getHandler(processedRequest);根据当前请求获取到能处理这个请求的Controller对象
3)、923:找到能执行这个Controller对象里面每一个方法的适配器
4)、945:ha.handle适配器调用目标方法(利用反射调用方法)
5)、959:转发到页面(处理响应结果)processDispatchResult
1、根据当前请求地址找到哪个处理器来处理请求 mappedHandler = getHandler(processedRequest);
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
SpringfMVC启动的时候扫描所有的注解,将每一个类的每一个方法能处理什么请求都已经保存在handlerMapping中了;DefaultAnnotationHandlerMapping;
2、为当前请求确定适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
找到能调用这个类里面每个方法的适配器;适配器利用反射调用方法;
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { 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"); }
我们都使用注解模式的所以适配器使用第三个;
3、SpringMVC中DispatcherServlet的几个重要属性,以及赋值
SpringMVC九大组件;
/** MultipartResolver used by this servlet 文件上传解析器*/ private MultipartResolver multipartResolver; /** LocaleResolver used by this servlet 国际化解析器*/ private LocaleResolver localeResolver; /** ThemeResolver used by this servlet 主题解析器*/ private ThemeResolver themeResolver; /** List of HandlerMappings used by this servlet 保存了请求与类的映射关系(哪个请求用哪个类来处理)*/ private List<HandlerMapping> handlerMappings; /** List of HandlerAdapters used by this servlet适配器;用来执行控制器(处理器)目标方法的*/ private List<HandlerAdapter> handlerAdapters; /** List of HandlerExceptionResolvers used by this servlet 异常解析器*/ private List<HandlerExceptionResolver> handlerExceptionResolvers; /** RequestToViewNameTranslator used by this servlet 转化器*/ private RequestToViewNameTranslator viewNameTranslator; /** FlashMapManager used by this servletFlashMap 管理器 */ private FlashMapManager flashMapManager; /** List of ViewResolvers used by this servlet视图解析器 */ private List<ViewResolver> viewResolvers;
文件上传组件默认没值;
默认赋值;
protected void initStrategies(ApplicationContext context) {
//默认从ioc容器中获取id为multipartResolver的组件,如果没有获取到就赋值为null;
initMultipartResolver(context);
//按照id获取localeResolver;如果没有;
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
//1、有些组件是这么》?先获取用户配置的,如果没有可以使用默认的(MultipartResolver )
//2、有些组件是拿id获取的;有些是拿类型获取的,
//3、给SpringMVC中配置九大之一的某个组件;如果是拿id'获取的?id不要乱写,用指定id;
//如果是用类型获取,id可以不用写;
在于DispatcherServlet.class同目录下有一个properties文件,这里封装了所有组件默认的类型;
4、目标方法的运行
AnnotationMethodHandlerAdapter----》handle()
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Class<?> clazz = ClassUtils.getUserClass(handler);
Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
if (annotatedWithSessionAttributes == null) {
annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
}
if (annotatedWithSessionAttributes) {
// Always prevent caching in case of session attribute management.
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
// Prepare cached set of session attributes names.
}
else {
// Uses configured default cacheSeconds setting.
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);
}
}
}
//执行处理器(控制器Controller)的目标方法
return invokeHandlerMethod(request, response, handler);
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取方法解析器 ServletHandlerMethodResolver methodResolver = getMethodResolver(handler); //根据当前请求路径,匹配每个方法的requestMapping值;并解析方法的详细信息 Method handlerMethod = methodResolver.resolveHandlerMethod(request); //获取方法的执行器 ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver); //包装request和response; ServletWebRequest webRequest = new ServletWebRequest(request, response); //创建了一个隐含模型 ExtendedModelMap implicitModel = new BindingAwareModelMap(); //真正执行目标方法; handlerMethod.invoke(handler,args) 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; }
invokeHandlerMethod
public final Object invokeHandlerMethod(Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); try { boolean debug = logger.isDebugEnabled(); for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); if (attrValue != null) { implicitModel.addAttribute(attrName, attrValue); } } //找到标注了ModelAttribute注解的所有方法,并执行 for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); //解析处理器的参数;确定当前方法要执行时要使用的所有参数; Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); if (debug) { logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); } //找到getBook方法的ModelAttribute注解的value值; String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { continue; } ReflectionUtils.makeAccessible(attributeMethodToInvoke); //执行方法,ModelAttribute标注的所有方法提前执行 Object attrValue = attributeMethodToInvoke.invoke(handler, args); if ("".equals(attrName)) { Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); } if (!implicitModel.containsAttribute(attrName)) { //将ModelAttribute标注的提前运行的方法的返回值放入隐含模型; implicitModel.addAttribute(attrName, attrValue); } } //确定目标方法每一个参数的值; 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; } }
HandlerMethodInvoker-->resolveHandlerArguments(确定目标方法使用的每一个参数值)
//确定参数值
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 MethodParameter(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.value(); required = requestParam.required(); defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); annotationsFound++; } else if (RequestHeader.class.isInstance(paramAnn)) { RequestHeader requestHeader = (RequestHeader) paramAnn; headerName = requestHeader.value(); 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.value(); required = cookieValue.required(); defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); annotationsFound++; } else if (PathVariable.class.isInstance(paramAnn)) { PathVariable pathVar = (PathVariable) paramAnn; pathVarName = pathVar.value(); annotationsFound++; } 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 if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) { validate = true; Object value = AnnotationUtils.getValue(paramAnn); validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value}); } } //以上注解不能标注多个 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); if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; } else if (defaultValue != null) { args[i] = resolveDefaultValue(defaultValue); } else { Class<?> paramType = methodParam.getParameterType(); //判断是否Model和Map旗下的,将隐含模型交给这个map类型的参数 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."); } args[i] = implicitModel;//存到map中 } else if (SessionStatus.class.isAssignableFrom(paramType)) { args[i] = this.sessionStatus; } else if (HttpEntity.class.isAssignableFrom(paramType)) { args[i] = resolveHttpEntityRequest(methodParam, webRequest); } else if (Errors.class.isAssignableFrom(paramType)) { throw new IllegalStateException("Errors/BindingResult argument declared " + "without preceding model attribute. Check your handler method signature!"); } //确定当前参数是否简单的基本类型参数;String,Integer ... else if (BeanUtils.isSimpleProperty(paramType)) { paramName = ""; } //赋值为attrName=""; else { attrName = ""; } } } //其他情况,有注解的情况,下边的某个if可能是成功的就会进行; if (paramName != null) { 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 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; }
resolveCommonArgument(解析普通参数)----resolveStandardArgument
确定参数是否可以传入的原生ServletAPI
@Override protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); 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; } 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; } else if (HttpSession.class.isAssignableFrom(parameterType)) { return request.getSession(); } else if (Principal.class.isAssignableFrom(parameterType)) { return request.getUserPrincipal(); } else if (Locale.class.equals(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); }
结论一:
提前运行的ModelAttribute方法的参数和目标方法的参数写法规则是一模一样的;
提前运行了ModelAttribute方法,隐含模型中会有两种东西?
1)、ModelAttribute方法Map作为参数时,给里面put的数据
2)、ModelAttribute方法返回值也放入map。
3)、都是给隐含模型中放置值
流程:
1)、获取所有参数类型,挨个确定每个参数对应值
2)、确定当前参数是否有注解;
有:保存注解的详细信息;
没有:往下走
3)、注解大于1抛异常(注解不合法),
4)、注解=0(没有注解),if -- else if
1)确定这个参数是否原生API;是则返回,
2)是否有默认值@Value("");没有
3)其他情况
1)、是否Model或者Map旗下的,是则将隐含模型赋值过来
2)、
5)、注解正好的情况(注解ok)
1)、其他注解
2)、ModelAttribute注解;
将ModelAttribute注解的value值赋值给attrName
6)、确定自定义类型对象;attrName肯定不是null
attrName的值:
1)、参数有ModelAttribute注解attrName就是注解标注的值
2)、参数没有ModelAttribute注解,attrName就是"";
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { // Bind request parameter onto object... String name = attrName; if ("".equals(name)) { name = Conventions.getVariableNameForParameter(methodParam); } Class<?> paramType = methodParam.getParameterType(); // Object bindObject; //1、判断隐含模型中是否有这个key,有则从隐含模型中获取到这个值赋值給bindObject; if (implicitModel.containsKey(name)) { bindObject = implicitModel.get(name); } //2、如果隐含模型中没有看是否是SessionAttributes标注的属性,如果是从Session中获取这个key的值,赋值给bindObject else if (this.methodResolver.isSessionAttribute(name, paramType)) { bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); //如果Session中没有查到这个值。抛异常; if (bindObject == null) { raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); } } //3、隐含模型中也没有这个key,SessionAttributes也没说它有。 else { // 利用反射创建出一个对象 bindObject = BeanUtils.instantiateClass(paramType); } //把bindObject传入,返回一个WebDataBinder(将请求传入的参数绑定到刚才创建的对象中); WebDataBinder binder = createBinder(webRequest, bindObject, name); initBinder(handler, name, binder, webRequest); return binder; }
执行目标方法并返回;
1)、确定自定义类型参数的值流程;
1、确定Book对象的attrName; 获取标注了ModelAttribute注解的value值;如果没有就是"";(给Book对象确定一个key)
2、一但key是"";把Book的类型首字符小写作为key
3、查这个key的值:
1)、判断隐含模型中是否存在这个key;如果有则返回,没有继续
2)、看是否是SessionAttributes标注的属性;是则查询(查不到抛异常)
3)、都不是,则利用反射创建对象;
4、将请求带来的每一个参数封装进这个对象中;
【7、SpringMVC如何解析方法返回值(视图)】
逻辑视图(方法返回值)转为物理视图(真实页面地址)的过程;
1)、任意方法的任意返回值,最终都会被包装成一个ModelAndView对象;返回出去;既包含了视图信息又包含了模型数据;
1)、方法执行完成以后,根据方法的返回值包装ModelAndView对象;
方法的返回值就是页面地址。隐含模型中的所有数据就是要给页面携带的数据;
AnnotationMethodHandlerAdapter----》handle()-----》invokeHandlerMethod()-----》 resolveModelAttribute()
//真正执行目标方法; handlerMethod.invoke(handler,args)
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
ModelAndView mav =
methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
//各种数据类型最终都会转换成ModelAndView 类型
@SuppressWarnings("unchecked") public ModelAndView getModelAndView(Method handlerMethod, Class<?> handlerType, Object returnValue, ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception { ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class); if (responseStatusAnn != null) { HttpStatus responseStatus = responseStatusAnn.value(); String reason = responseStatusAnn.reason(); if (!StringUtils.hasText(reason)) { webRequest.getResponse().setStatus(responseStatus.value()); } else { webRequest.getResponse().sendError(responseStatus.value(), reason); } // to be picked up by the RedirectView webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, responseStatus); responseArgumentUsed = true; } // Invoke custom resolvers if present... if (customModelAndViewResolvers != null) { for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) { ModelAndView mav = mavResolver.resolveModelAndView( handlerMethod, handlerType, returnValue, implicitModel, webRequest); if (mav != ModelAndViewResolver.UNRESOLVED) { return mav; } } } if (returnValue instanceof HttpEntity) { handleHttpEntityResponse((HttpEntity<?>) returnValue, webRequest); return null; } else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) { handleResponseBody(returnValue, webRequest); return null; } else if (returnValue instanceof ModelAndView) { ModelAndView mav = (ModelAndView) returnValue; mav.getModelMap().mergeAttributes(implicitModel); return mav; } else if (returnValue instanceof Model) { return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap()); } else if (returnValue instanceof View) { return new ModelAndView((View) returnValue).addAllObjects(implicitModel); } else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) { addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); return new ModelAndView().addAllObjects(implicitModel); } else if (returnValue instanceof Map) { return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map<String, ?>) returnValue); } else if (returnValue instanceof String) { return new ModelAndView((String) returnValue).addAllObjects(implicitModel); } else if (returnValue == null) { // Either returned null or was 'void' return. if (this.responseArgumentUsed || webRequest.isNotModified()) { return null; } else { // Assuming view name translation... return new ModelAndView().addAllObjects(implicitModel); } } else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) { // Assume a single model attribute... addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); return new ModelAndView().addAllObjects(implicitModel); } else { throw new IllegalArgumentException("Invalid handler method return value: " + returnValue); } }
2、959:处理返回值processDispatchResult;
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
1)、视图解析器负责将返回值解析创建出视图对象
2)、视图对象决定模型数据如何渲染(数据怎么展示);页面如何跳转;
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; //1、有异常处理异常 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.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) { mappedHandler.triggerAfterCompletion(request, response, null); } }
Render方法的内部
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.resolveLocale(request); response.setLocale(locale); View view; if (mv.isReference()) { // 1)We need to resolve the view name.视图解析器要根据返回值创建视图对象了 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 {
//2)、视图对象进行渲染 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; } }
1)We need to resolve the view name.视图解析器要根据返回值创建视图对象了
View:这是一个接口;
ViewResolver:也是一个接口;
ViewResolver创建出View对象,View对象负责页面信息的渲染
ViewResolver:用户可以配置多个
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { //多个视图解析器依次解析,如果某个解析成功就直接返回值;如果没有成功下一个解析器继续 for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale);//createView()在里面 if (view != null) { return view; } } return null; }
viewResolver 根据视图名得到视图对象;resolveViewName细节;在InternalResourceViewResovler的父类中定义了创建视图对象这个方法
view = createView(viewName, locale);
@Override protected View createView(String viewName, Locale locale) throws Exception { // If this resolver is not supposed to handle the given view, // return null to pass on to the next resolver in the chain. if (!canHandle(viewName, locale)) { return null; } // Check for special "redirect:" prefix.如果是redirect:开始的、创建一个有重定向功能的视图对象; if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); return applyLifecycleMethods(viewName, view); } // Check for special "forward:" prefix.如果是以forward:前缀开始,创建一个具有转发功能的视图对象; if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); return new InternalResourceView(forwardUrl); } // Else fall back to superclass implementation: calling loadView.否则创建一个默认的View对象 //InternalResourceView;默认的是有国际化功能的; return super.createView(viewName, locale); }
2)、视图对象进行渲染
视图对象进行渲染:DispatcherServlet---1225
@Override 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<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); //渲染模型数据;Merged:合并
renderMergedOutputModel(mergedModel, request, response); }
视图对象如何渲染;
@Override protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine which request handle to expose to the RequestDispatcher. HttpServletRequest requestToExpose = getRequestToExpose(request); // Expose the model object as request attributes.将模型中的数据暴露到request域中;底层也是把隐含模型这个map中所有的key遍历都放在request域中 exposeModelAsRequestAttributes(model, requestToExpose); // Expose helpers as request attributes, if any. exposeHelpers(requestToExpose); // Determine the path for the request dispatcher.拿到转发的地址 String dispatcherPath = prepareForRendering(requestToExpose, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). RequestDispatcher rd = getRequestDispatcher(requestToExpose, 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(requestToExpose, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } rd.include(requestToExpose, 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(requestToExpose, response); } }
1、视图解析器负责根据返回值作为页面地址得到视图对象
2、视图对象调用渲染方法;
3、视图对象渲染(页面跳转逻辑,模型数据放在请求域中)
InternalResourceView:转发到页面
RedirectView:重定向到页面
JSTLView:快速国际化;只要导入了jstl的jar包,以前默认创建的InternalResouceView都会被使用jstlView替代;
国际化的新步骤:
1)、写好国际化资源文件
2)、在SpringMVC配置文件中配置管理国际化资源文件的消息管理器组件
<!-- 注册一个国际化资源管理器;id必须是messageSource --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="i18n"></property> </bean>
3)、去页面 使用fmt:message标签取值即可
因为追求卓越,成功在不经意间追上了你