Java-第十五部分-源码解读-异常处理、界面渲染处理和EnableWebMvc机制

474 阅读3分钟

源码解读全文

processDispatchResult

  • 发生在adapter执行完方法,获取ModelAndView后,处理后续processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

异常处理

  • 异常处理器,在初始化九大组件时,进行装配 image.png
  • 处理异常获得一个ModelAndViewmv = processHandlerException(request, response, handler, exception);,遍历异常解析器进行异常处理 image.png
  1. ExceptionHandlerExceptionResolver,用自定义的异常处理器处理,自定义异常处理器注解@ControllerAdvice,其中的方法用注解@ExceptionHandler,处理哪些异常
  2. ResponseStatusExceptionResolver注解了@ResponseStatus的异常类,根据自定义异常信息response.sendError(statusCode);
  3. DefaultHandlerExceptionResolver是否为指定的异常,直接展示错误页response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());,返回空的ModelAndView
  • 如果都解析不了,再次抛出异常,直到抛给tomcat,返回500默认错误页

ExceptionHandlerExceptionResolver初始化

  • 初始化流程,利用InitliazingBean时,进行初始化赋值
  • initExceptionHandlerAdviceCache();初始化@ExceptionHandler的方法缓存
  • 找出ControllerAdvice注解的BeanList<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); image.png
  • 对每一个Bean进行解析,扫描出所有注解@ExceptionHandler的方法,用Map缓存,ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);

保存的形式为controllerAdvice - methods image.png

  • 处理参数解析器和返回值解析器 image.png

ExceptionHandlerExceptionResolver执行

  • 重写了doResolveHandlerMethodException
  • exceptionHandlerCache处理该异常的方法,ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
  1. 遍历该异常处理Bean的所有方法,进行匹配
  2. 多个能处理,就返回第一个
  • 准备参数解析器和返回值解析器,
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

  • 通过视图解析器进行处理 image.png image.png
  • 调用AbstractCachingViewResolverresolveViewName
  • 创建出view对象,view = createView(viewName, locale);
  1. 如果为重定向redirect:开头,创建RedirectView
  2. 如果为转发forward:开头,创建InternalResourceView
  3. 调用父类创建InternalResourceView

view.render

  • 准备数据Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
  • 准备请求和响应prepareResponse(request, response);
  • 渲染模型renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
  1. InternalResourceView的类中
  2. 暴露model中的数据作为请求域中的数据,exposeModelAsRequestAttributes(model, request);,如果有值为添加,无值为移除
  3. 准备视图的访问路径String dispatcherPath = prepareForRendering(request, response);
  4. 获取请求转发器RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
  5. 请求转发rd.forward(request, response);
  • RedirectView渲染底层
  1. 闪存数据flashMap,通过RedirectAttributes中的FlashAttribute,进行数据共享RequestContextUtils.saveOutputFlashMap(targetUrl, request, response);,从request域中获取,放到session中,表单提交中应用
  2. 调用response.sendRedirect(encodedURL);

拦截器处理

mappedHandler.triggerAfterCompletion(request, response, null);

EnableWebMvc+WebMvcConfigurer

  • WebMvcConfigurer预留了mvc的扩展接口
  • 导入SpringMVC的核心组件,并可以对其拓展

访问者模式,将内容与修改分开,configurers为访问者,定义了每一种组件的访问方法

EnableWebMvc

  • @EnableWebMvc中导入了DelegatingWebMvcConfiguration image.png
  • DelegatingWebMvcConfiguration进行configurer的自动装配,获得所有的WebMvcConfigurer image.png
  • 功能增强,都是通过this.configurers调用 image.png image.png
  • 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为例

image.png

  • 如果为空,且只有一个ViewResolver的定义,就放InternalResourceViewResolver image.png
  • ViewResolverComposite作为最终的ViewResolver,实现了ViewResolver接口,其中有集合维护了所有的ViewResolver image.png
  • DispatcherServlet中初始化九大组件,能被找到 image.png

addArgumentResolvers

  • 重写getArgumentResolvers中的add方法 image.png
  • 当生成requestMappingHandlerAdapterBean时,调用adapter.setCustomArgumentResolvers(getArgumentResolvers());,添加到customArgumentResolvers image.png
  • 而当RequestMappingHandlerAdapter调用afterPropertiesSet进行初始化时,会处理customArgumentResolvers image.png