源码解读全文
processDispatchResult
- 发生在
adapter执行完方法,获取ModelAndView后,处理后续processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
异常处理
- 异常处理器,在初始化九大组件时,进行装配
- 处理异常获得一个
ModelAndView,mv = processHandlerException(request, response, handler, exception);,遍历异常解析器进行异常处理
ExceptionHandlerExceptionResolver,用自定义的异常处理器处理,自定义异常处理器注解@ControllerAdvice,其中的方法用注解@ExceptionHandler,处理哪些异常ResponseStatusExceptionResolver注解了@ResponseStatus的异常类,根据自定义异常信息response.sendError(statusCode);DefaultHandlerExceptionResolver是否为指定的异常,直接展示错误页response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());,返回空的ModelAndView
- 如果都解析不了,再次抛出异常,直到抛给
tomcat,返回500默认错误页
ExceptionHandlerExceptionResolver初始化
- 初始化流程,利用
InitliazingBean时,进行初始化赋值 initExceptionHandlerAdviceCache();初始化@ExceptionHandler的方法缓存- 找出
ControllerAdvice注解的Bean,List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); - 对每一个
Bean进行解析,扫描出所有注解@ExceptionHandler的方法,用Map缓存,ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
保存的形式为
controllerAdvice - methods
- 处理参数解析器和返回值解析器
ExceptionHandlerExceptionResolver执行
- 重写了
doResolveHandlerMethodException - 从
exceptionHandlerCache处理该异常的方法,ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
- 遍历该异常处理
Bean的所有方法,进行匹配- 多个能处理,就返回第一个
- 准备参数解析器和返回值解析器,
if (this.argumentResolvers != null) {
exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
- 反射执行,与执行请求方法一致,
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
视图渲染
- 使用视图解析器,将返回的视图名,解析成真正的
view对象进行渲染 render(mv, request, response);
将逻辑视图(资源名)转换为真正的视图,通过渲染转为了实际的显示
- 国际化信息处理
Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
根据请求头的
Accept-Language获取
- 获取视图名,逻辑视图
String viewName = mv.getViewName(); - 解析视图名,变为视图对象
view = resolveViewName(viewName, mv.getModelInternal(), locale, request); - 进行渲染,
view.render(mv.getModelInternal(), request, response);
resolveViewName
- 通过视图解析器进行处理
- 调用
AbstractCachingViewResolver的resolveViewName - 创建出
view对象,view = createView(viewName, locale);
- 如果为重定向
redirect:开头,创建RedirectView- 如果为转发
forward:开头,创建InternalResourceView- 调用父类创建
InternalResourceView
view.render
- 准备数据
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); - 准备请求和响应
prepareResponse(request, response); - 渲染模型
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
InternalResourceView的类中- 暴露
model中的数据作为请求域中的数据,exposeModelAsRequestAttributes(model, request);,如果有值为添加,无值为移除- 准备视图的访问路径
String dispatcherPath = prepareForRendering(request, response);- 获取请求转发器
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);- 请求转发
rd.forward(request, response);;
RedirectView渲染底层
- 闪存数据
flashMap,通过RedirectAttributes中的FlashAttribute,进行数据共享RequestContextUtils.saveOutputFlashMap(targetUrl, request, response);,从request域中获取,放到session中,表单提交中应用- 调用
response.sendRedirect(encodedURL);
拦截器处理
mappedHandler.triggerAfterCompletion(request, response, null);
EnableWebMvc+WebMvcConfigurer
WebMvcConfigurer预留了mvc的扩展接口- 导入
SpringMVC的核心组件,并可以对其拓展
访问者模式,将内容与修改分开,
configurers为访问者,定义了每一种组件的访问方法
EnableWebMvc
@EnableWebMvc中导入了DelegatingWebMvcConfigurationDelegatingWebMvcConfiguration进行configurer的自动装配,获得所有的WebMvcConfigurer- 功能增强,都是通过
this.configurers调用 DelegatingWebMvcConfiguration的父类WebMvcConfigurationSupport,其中包括了很多@Bean的方法,导入了九大组件,过程中存在模板方法,能够让子类自定义组件进行添加,通过add方法簇,调用configurer进行添加
通过导入配置类的方式,会对组件进行
Bean注入,直接装配组件,装配过程中,通过添加进了BeanFactory
自定义配置
- 需要作为
SpringMVC的配置类
@EnableWebMvc
@Configuration
public class MyExtendConfiguration implements WebMvcConfigurer {
@Override
//配置视图解析器
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.viewResolver(new MyViewResolver());
registry.viewResolver(new InternalResourceViewResolver());
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new MyArgymentResolver());
}
}
ViewResolver为例
- 如果为空,且只有一个
ViewResolver的定义,就放InternalResourceViewResolver ViewResolverComposite作为最终的ViewResolver,实现了ViewResolver接口,其中有集合维护了所有的ViewResolverDispatcherServlet中初始化九大组件,能被找到
addArgumentResolvers
- 重写
getArgumentResolvers中的add方法 - 当生成
requestMappingHandlerAdapter的Bean时,调用adapter.setCustomArgumentResolvers(getArgumentResolvers());,添加到customArgumentResolvers - 而当
RequestMappingHandlerAdapter调用afterPropertiesSet进行初始化时,会处理customArgumentResolvers