spring MVC源码解析
1、前端控制器的架构?
可知springmvc处理请求的核心方法就是doDispatch()方法
2.前端控制器的核心方法doDispatch()
源码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//1、检查是否文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//2、根据当前的请求地址找到那个类能来处理;拿到执行链
mappedHandler = getHandler(processedRequest);
//3、如果没有找到哪个处理器(控制器)能处理这个请求就404,或者抛异常
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
//4、拿到能执行这个类的所有方法的适配器;(反射工具AnnotationMethodHandlerAdapter)
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()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行所有拦截器的preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//控制器(Controller),处理器(Handler)
//5、适配器来执行目标方法;将目标方法执行完成后的返回值作为视图名,设置保存到ModelAndView中
//目标方法无论怎么写,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView
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);
}
//转发到目标页面;
//6、根据方法最终执行完成后封装的ModelAndView;转发到对应页面,而且ModelAndView中的数据可以从请求域中获取
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
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);
}
}
}
}
总结DispatcherServlet流程
1.、所有请求过来DispatcherServlet收到请求,
2.、调用doDispatch()方法进行处理
1、getHandler():根据当前请求地址找到能处理这个请求的目标处理器类(处理器)
根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
2、getHandlerAdapter():根据当前处理器类获取到能执行这个处理器方法的适配器;
根据当前处理器类,找到当前类的HandlerAdapter(适配器)
3.、使用刚才获取到的适配器(AnnotationMethodHandlerAdapter )执行目标方法;
4.、目标方法执行后会返回一个ModelAndView对象
5.、根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView中的模型数据
第一检查是否是文件上传这里就不细讲了,知道有这个流程就行
重点是这个getHandler(processedRequest)方法 : 根据当前请求地址找到能处理这个请求的目标处理器类(处理器)
3.获取Handle(处理器):getHandler(processedRequest) 方法
源码
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
//遍历 HandlerMapping 通过请求路径找到Handel
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;
}
getHandler()会返回目标处理器类的执行链;HandelExecutionChain
HandlerMapping 处理器映射:他里面保存了每一个处理器能处理哪些请求的映射信息;
handlerMap:ioc容器启动创建Controller对象的时候扫描每个处理器都能处理什么请求,保存在HandlerMapping的handlerMap属性中;
下一次请求过来,就来看哪个HandlerMapping中有这个请求映射信息就行了;
3.获取HandleAdpter(处理器适配器):getHandlerAdapter(mappedHandler.getHandler()) 方法
源码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
//遍历handlerAdapters 判断当前的处理器适配器是否支持这个handler
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");
}
拿HandlerAdapter适配器去执行目标方法
处理方法的具体执行流程
4.handle(processedRequest, response, mappedHandler.getHandler())
源码
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
这里会跳转执行handleInternal(request, response, (HandlerMethod) handler) 方法
4.1:handleInternal(request, response, (HandlerMethod) handler)
源码
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// 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) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
由上源码知道 真正执行的方法又跳到了 mav = invokeHandlerMethod(request, response, handlerMethod)
4.2.nvokeHandlerMethod(request, response, handlerMethod)
源码
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//创建了一个数据绑定的工厂
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
//将model与binderFactory进行一下 绑定
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//创建了一个方法执行器-->执行方法
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
//设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
//设置HandlerMethod的返回值解析器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
//将方法执行器与binderFactory进行一下 绑定
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
//创建ModelAndViewContainer 称之为隐含模型
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
//初始化操作
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();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
//执行处理方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
4.3.invocableMethod.invokeAndHandle(webRequest, mavContainer);
源码
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//又又又跳转了
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
//后面是一些对返回值的 处理操作
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
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(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
4.4.invokeForRequest(webRequest, mavContainer, providedArgs)
源码
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//解析出方法执行需要的参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
//方法执行
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
4.4.1参数获取: Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs)
源码
private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//先获取到所有的参数
MethodParameter[] parameters = getMethodParameters();
//创建了一个和参数个数一样的数组,会用来保存每一个参数的值
Object[] args = new Object[parameters.length];
//循环的去遍历赋值
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
//此处解析参数设置
args[i] = resolveProvidedArgument(parameter, providedArgs);
//如果上面步骤设置了,进入下次一循环
if (args[i] != null) {
continue;
}
//获取能解析出方法参数值的参数解析器
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
//解析出参数值
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
}
throw ex;
}
}
//如果没有能解析方法参数的类,抛出异常
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
4.4.1获取方法参数解析器:this.argumentResolvers.supportsParameter(parameter)
源码
public boolean supportsParameter(MethodParameter parameter) {
//跳转了
return (getArgumentResolver(parameter) != null);
}
4.4.2这个方法真正获取方法参数解析器:HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter)
源码
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//先看之前有没有解析过这个方法参数,如果解析过,则从缓存中取
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
//循环所有的参数解析类,匹配真正参数解析的类
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
//检查当前你遍历的参数解析器是否支持当前参数的解析,支持就存入参数解析器的缓存中
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
//放到缓存中
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
}
4.4.3检查当前参数解析器是否支持解析当前数:supportsParameter(MethodParameter parameter)
源码
@Override
public boolean supportsParameter(MethodParameter parameter) {
//方法的参数中是否有RequestParam注解。
if (parameter.hasParameterAnnotation(RequestParam.class)) {
//参数是否是 Map类型的
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && StringUtils.hasText(requestParam.name()));
}
else {
return true;
}
}
else {
//如果有RequestPart注解,直接返回faslse
if (parameter.hasParameterAnnotation(RequestPart.class)) {
return false;
}
parameter = parameter.nestedIfOptional();
//是否是文件上传中的值
if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
return true;
}
//
else if (this.useDefaultResolution) {
//判断是否是简单类型参数
return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
}
else {
return false;
}
}
}
在上面的代码中我们可以看到,请求对应的处理方法的中的参数如果带有RequestParam注解,则判断是不是Map类型的参数,如果不是,则直接返回true。
如果没有RequestParam注解,则判断如果有RequestPart注解,则直接返回false,接着判断是否是文件上传表单中的参数值,如果不是,则接着判断useDefaultResolution是否为true。
这里需要说明一下的是: argumentResolvers中有两个RequestParamMethodArgumentResolver bean, 一个useDefaultResolution为false,一个useDefaultResolution为true。当useDefaultResolution为false的bean是用来处理RequestParam注解的,useDefaultResolution为true的bean是用来处理简单类型的bean的。在我们这个例子中,useDefaultResolution的值为true。那么接下来回判断是不是简单类型参数,我们进到BeanUtils.isSimpleProperty这个方法中看一下:
4.4.4BeanUtils.isSimpleProperty(parameter.getNestedParameterType())
源码
public static boolean isSimpleProperty(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
return isSimpleValueType(clazz) || (clazz.isArray() && isSimpleValueType(clazz.getComponentType()));
}
4.4.5:isSimpleValueType()
源码
public static boolean isSimpleValueType(Class<?> clazz) {
return (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() ||
CharSequence.class.isAssignableFrom(clazz) ||
Number.class.isAssignableFrom(clazz) ||
Date.class.isAssignableFrom(clazz) ||
URI.class == clazz || URL.class == clazz ||
Locale.class == clazz || Class.class == clazz);
}
真正进行类型判断的方法是isSimpleValueType这个方法,如果请求对应处理类的方法的参数为 枚举类型、String类型、Long、Integer、Float、Byte、Short、Double、Date、URI、URL、Locale、Class、文件上传对象或者参数是数组,数组类型为上面列出的类型则返回true。即 我们的请求对应处理类的方法的参数为:枚举类型、String类型、Long、Integer、Float、Byte、Short、Double、Date、URI、URL、Locale、Class、文件上传对象或者参数是数组,数组类型为上面列出的类型,则请求参数处理类为:RequestParamMethodArgumentResolver。我们先看一下RequestParamMethodArgumentResolver的UML类图关系:
4.4.6:上面都是对参数解析器的获取:接下看看参数时怎么解析的resolveArgument()
源码
@Override
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//获取请求对应处理方法的参数字段值
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
MethodParameter nestedParameter = parameter.nestedIfOptional();
//解析之后的请求对应处理方法的参数字段值
Object resolvedName = resolveStringValue(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
//解析参数值
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
//如果从请求中得到的参数值为null的话
if (arg == null) {
//判断是否有默认值
if (namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}//判断这个字段是否是必填,RequestParam注解默认为必填。
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}//处理null值
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}//如果为得到的参数值为null,且有默认的值
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
//参数的校验
if (binderFactory != null) {
//参数校验
}
//空实现
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
4.4.7NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
源码
private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
//先从缓存中获取
NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
//缓存中不存在这个值
if (namedValueInfo == null) {
//创建NamedValueInfo对象
namedValueInfo = createNamedValueInfo(parameter);
//更新刚才得到的NamedValueInfo对象
namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
//放入缓存中
this.namedValueInfoCache.put(parameter, namedValueInfo);
}
return namedValueInfo;
}
5.处理方法的执行:Object returnValue = doInvoke(args)
源码
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(getInvocationErrorMessage(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 {
String text = getInvocationErrorMessage("Failed to invoke handler method", args);
throw new IllegalStateException(text, targetException);
}
}
}
5.1.getBridgedMethod().invoke(getBean(), args)
源码
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
//方法执行
return ma.invoke(obj, args);
}
5.2.ma.invoke(obj, args)
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
//跳转
return this.delegate.invoke(var1, var2);
}
5.3.this.delegate.invoke(var1, var2)
源码
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(var3);
}
//执行目标方法
return invoke0(this.method, var1, var2);
}
5.4.invoke0(this.method, var1, var2) 此处就执行目标方法了—>测试的方法
目标测试方法执行跳转不必深究,此处只是记录过程,知道是用反射的方式执行 目标方法就行
重点是参数的设置Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
在执行目标方法前设置好好方法执行需要的参数列表
6.返回ModelAadView :getModelAndView()
源码
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
无论你处理方法中返回的什么,在源码底层都是给你返回给你一个ModelAndView—>根据ModelAndView用viewResolver解析返回一个View–>view 对数据进行渲染,请求转发
6.1.视图解析:processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)
源码
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?
//ModelAndView mv 不为null开始视图解析
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);
}
}
6.1.1:方法进渲染页面请求转发:render(mv, request, response);
源码
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的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.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;
}
}
6.1.1.1:view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
源码
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
//使用视图解析器解析返回View
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
6.1.1.1.1:视图解析器解析返回 视图:viewResolver.resolveViewName(viewName, locale);
源码
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) {
// Ask the subclass to create the View object.
//创建视图
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);
}
}
6.1.1.1.1.1.1:view = this.viewCreationCache.get(cacheKey);
源码
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.
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
//创建 "redirect:/..." 重定向的RedirectView
RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
String[] hosts = getRedirectHosts();
if (hosts != null) {
view.setHosts(hosts);
}
return applyLifecycleMethods(viewName, view);
}
// Check for special "forward:" prefix.
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
创建 "forward:/..." 请求转发InternalResourceView
return new InternalResourceView(forwardUrl);
}
// Else fall back to superclass implementation: calling loadView.
//创建其他类型的View-->里面细节感兴趣的可用自己去看看
return super.createView(viewName, locale);
}
上面过程已经得到了一个View对象:下面执行View的render()方法 渲染要输出给页面的所有数据
返回View对象;
1、视图解析器得到View对象的流程就是,所有配置的视图解析器都来尝试根据视图名(返回值)得到View(视图)对象;如果能得到就返回,得不到就换下一个视图解析器;
2、调用View对象的render方法;
6.1.2:view.render(mv.getModelInternal(), request, response)
源码
public void render(@Nullable 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);
}
6.3.1:renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
源码
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
//将模型Map model中的数据放在请求域中
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
//确定请求调度程序的路径。
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
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);
}
}
视图解析器只是为了得到视图对象;视图对象才能真正的转发(将模型数据全部放在请求域中)或者重定向到页面
视图对象才能真正的渲染视图;
7.DispatcherServlet 九大组件
源码
/** Well-known name for the MultipartResolver object in the bean factory for this namespace. */
//文件上传解析器
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
/** Well-known name for the LocaleResolver object in the bean factory for this namespace. */
//区域信息解析器;和国际化有关
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
/** Well-known name for the ThemeResolver object in the bean factory for this namespace. */
//主体解析器 强大的主题效果更换
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
/**
* Well-known name for the HandlerMapping object in the bean factory for this namespace.
* Only used when "detectAllHandlerMappings" is turned off.
* @see #setDetectAllHandlerMappings
*/
//处理器映射器 通过处理器映射器-->找到 处理器Handler
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
/**
* Well-known name for the HandlerAdapter object in the bean factory for this namespace.
* Only used when "detectAllHandlerAdapters" is turned off.
* @see #setDetectAllHandlerAdapters
*/
//处理器适配器-->通过处理器找到处理器适配器,用 是配置去执行处理方法
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
/**
* Well-known name for the HandlerExceptionResolver object in the bean factory for this namespace.
* Only used when "detectAllHandlerExceptionResolvers" is turned off.
* @see #setDetectAllHandlerExceptionResolvers
*/
//处理异常解析器
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
/**
* Well-known name for the RequestToViewNameTranslator object in the bean factory for this namespace.
*/
//ViewResolver是根据ViewName查找VIew,但有的Handler处理完后并没有设置View也没有ViewName,这时需要从request获 取viewName,RequestToViewNameTranslator就是做这个事情。
//RequestToViewNameTranslator在SpringMVC容器中只可以配置一个,所有request到ViewName的转换规则都要在一个 Translator里面全部实现。
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
/**
* Well-known name for the ViewResolver object in the bean factory for this namespace.
* Only used when "detectAllViewResolvers" is turned off.
* @see #setDetectAllViewResolvers
*/
//视图解析器
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
/**
* Well-known name for the FlashMapManager object in the bean factory for this namespace.
*/
//FlashMap+Manager:SpringMVC中运行重定向携带数据的功能
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
7.1:九大组件的初始化
源码
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
组件初始化具体细节博主就不写了–>要吐血了
组件的初始化:
有些组件在容器中是使用类型找的,有些组件是使用id找的;
去容器中找这个组件,如果没有找到就用默认的配置;