1. Spring Web MVC 1.1. DispatcherServlet
DispacherServlet 为请求处理提供了共享的算法,而实际的工作则由可配置的代理组件执行。
1.1.1. Context HierarchyDispacherServlet 拥有一个属于它自己配置的 WebApplicationContext
1.1.2. Special Bean TypesDispatcherServlet 委托特殊的 bean 来处理请求并响应。具体见官网列表。
1.1.3. Web MVC ConfigDispatcherServlet 会为每个特殊 bean 检查 WebApplicationContext。如果没有匹配的 bean 类型,则会回退到使用 DispatcherServlet.properties 的默认 bean。
1.1.4. Servlet ConfigServlet 3.0+ 允许使用编程方式进行 Servlet 配置。
WebApplicationInitializer 是由 Spring MVC 提供的接口,可以确保检测到您的实现并用于初始化任何 Servlet 3 容器。
底层原理
Tomcat 具有 WebappServiceLoader,以 SPI 方式提供了 ServletContainerInitializer
见 spring-web-5.2.15.RELEASE.jar!meta-INFservicesjavax.servlet.ServletContainerInitializer
其中只有一行 org.springframework.web.SpringServletContainerInitializer,此类用于收集 WebApplicationInitializer 所有实现类
1.1.7. Exceptions如果请求映射期间或者请求处理程序(如 @Controller)抛出异常,则 DispatcherServlet 将委托给 HandlerExceptionResolver 解析异常,并提供替代处理,这是典型的错误响应。
Spring Boot 见 ErrorMvcAutoConfiguration
Chain of Resolvers可以通过 HandlerExceptionResolver 在 Spring 配置中声明多个 bean 并根据需要设置他们的 order 属性。order 越高,异常处理器位置越靠后(越晚处理)。
HandlerExceptionResolver 约定可以返回如下:
- ModelAndView 跳转到错误页面
- 如果在解析器里处理了异常,则可以返回一个空的 ModelAndView
- 如果异常仍未处理,则返回 null,供后续解析器继续尝试,如果异常一直存在,允许冒泡到 Servlet 容器。
如果一直没有 HandlerExceptionResolver 处理异常,或者响应状态为错误(4xx、5xx),则 Servlet 容器可以在 HTML 中呈现默认的错误页面。要自定义容器的默认错误页面,可以在 web.xml 声明:
Controller Advice/error
全局异常处理 @RestControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = AuthenticationException.class)
public ResponseDTO AuthenticationExceptionHandler(AuthenticationException e) {
return ResponseDTO.failure(e.getMessage());
}
}
*** ControllerAdvice 处理 Filter 抛出的异常
类比,Sturts 拦截器组,第一个就是 exception 拦截器。本质上是借助过滤器栈,将异常处理的过滤器放在第一个位置。
定义 ExceptionFilter,将捕捉的异常交给异常处理的 Controller。其他的过滤器不用处理异常,直接 throw 即可。
请务必调用 setOrder 方法,保持 order 值最大,这样过滤就能排在第一个。
@Component
@Order(Integer.MIN_VALUE)
public class ExceptionFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (IOException e) {
request.setAttribute("ioException", e);
request.getRequestDispatcher("/error").forward(request, response);
} catch (ServletException e) {
request.setAttribute("servletException", e);
request.getRequestDispatcher("/error").forward(request, response);
}
}
}
定义抛出异常的 Mapping
@PostMapping("/error")
public ResponseVO throwException(HttpServletRequest request) throws Exception {
throw (Exception) request.getAttribute("exception");
}
1.7. CORS
参考链接:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
1.7.1. Introduction 1.7.2. Processing 1.7.3. @CrossOrigin@CrossOrigin 可以用于:
- Controller 的方法,开启 Controller 方法级别的跨域请求
- Controller 类,由所有方法继承
默认,@CrossOrigin 允许:
- 所有 origin
- 所有 header
- 所有 HTTP 方法
allowedCredentials 默认不启用
maxAge 默认 30 分钟
除了细粒度的控制外,也可以通过实现 WebMvcConfigurer.addCorsMappings 定义全局 CORS 配置,参考代码见官网。
具体原理可见 DefaultCorsProcessor。



