1 静态资源配置原理
1、SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
2、SpringMVC功能的自动配置类 WebMvcAutoConfiguration,生效
//非代理配置类
@Configuration(proxyBeanMethods = false)
//web程序是servlet类型本自动配置类才生效
@ConditionalOnWebApplication(type = Type.SERVLET)
//有这些类才本自动配置类才生效
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//没有所示类本自动配置类才生效;去掉所示类后全面接管web和mvc配置
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
//配置类加载顺序
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
//配置类加载顺序
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
//.....................................
// Defined as a nested config to ensure WebMvcConfigurer is not read when not
// on the classpath
@Configuration(proxyBeanMethods = false)
//注册所示类,该类属WebMvcAutoConfiguration的静态内部类
@Import(EnableWebMvcConfiguration.class)
//配置文件的相关属性与所示类进行绑定:prefix = "spring.mvc";prefix = "spring.resources"
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
//.....................................
//有参构造器所有参数的值都会从容器中确定
//ResourceProperties resourceProperties;获取和spring.resources绑定的所有的值的对象
//WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象
//ListableBeanFactory beanFactory Spring的beanFactory
//HttpMessageConverters 找到所有的HttpMessageConverters
//******ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。********
//DispatcherServletPath
//ServletRegistrationBean 给应用注册Servlet、Filter....
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}
//...................................................................
@Override
//增加资源处理器参;参数是资源处理器注册处
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//如果配置文件:resources:{add-mappings: false}即禁用静态映射规则就停止本函数
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
//静态资源缓存时长(秒);获取自配置文件resources:{cache:{period: 12000}}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
//缓存控制策略获取自配置文件resources:{cache:{htmlApplicationCache:false}}
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
//如果注册处没有/webjars/**模式的映射
if (!registry.hasMappingForPattern("/webjars/**")) {
//就通过定制资源处理器注册方法来注册静态资源处理器
//(实质上是当前资源处理器的注册信息(ResourceHandlerRegistraction添加到注册处registry的注册表中List<ResourceHandlerRegistration>)
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
//静态资源路径模式获取自resources:{mvc:{static-path-pattern: /res/**}}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
2 Rest原理
Rest映射通过HiddenHttpMethodFilter实现,
基本原理:拦截器拦截post请求后用请求包装类更改请求的请求方式字符串,后放行,
其@bean方法在WebMvcAutoConfiguration类里:
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
//配置了enable才生效
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
HiddenHttpMethodFilter:
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
/** Default method parameter: {@code _method}. */
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
//Set the parameter name to look for HTTP methods.
public void setMethodParam(String methodParam) {
Assert.hasText(methodParam, "'methodParam' must not be empty");
this.methodParam = methodParam;
}
@Override//拦截请求处理方法
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletRequest requestToUse = request;
//若是post请求方式且请求参数无异常
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
//获取键_method的值
String paramValue = request.getParameter(this.methodParam);
//若值非空
if (StringUtils.hasLength(paramValue)) {
//值被转化为大写
String method = paramValue.toUpperCase(Locale.ENGLISH);
//若List<String> ALLOWED_METHODS含有该值
if (ALLOWED_METHODS.contains(method)) {
//则通过以下方法更新请求对象的请求方式字符串
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
//带着新的请求对象放行
filterChain.doFilter(requestToUse, response);
}
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}
@Override//包装类重写getMethod()方法
public String getMethod() {
return this.method;
}
}
}
3 请求映射原理
1.1 dispatcherServlet的继承树
1、dispatcherServlet的继承树
HttpServletBean的请求处理:
未重写请求doGet;
FrameworkServlet的请求处理:
@Override
//...................................
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//请求处理方法
processRequest(request, response);
}
//...................................
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
//请求处理服务
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
}
DispatcherServlet的请求处理:
未重写请求doGet,使用上面继承的doGet但doService重写了;
doDispatch是DispatcherServlet的核心方法,做处理和转发不仅是doGet,
所有的请求都调用doDispatch来处理;
所有mvc源码分析都应该从doDispatch开始。
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception {
//..............................
//doDispatch是DispatcherServlet的核心方法,做处理和转发
try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
1.2 核心方法doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//请求对象
HttpServletRequest processedRequest = request;
//handler执行链
HandlerExecutionChain mappedHandler = null;
//是否文件上传请求默认false
boolean multipartRequestParsed = false;
//异步管理器用于管理异步请求
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否文件上传请求
processedRequest = checkMultipart(request);
//检测到是文件上传就改变标记位true
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
**********//关键点:找当前请求使用哪个handler(controller的方法)处理分析见1.2.1
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {//如果没有找不到
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
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);
}
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);
}
}
}
}
}
1.3 getHandler(processedRequest)
//方法属于DispatcherServlet
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
4 暂停源码分析!
5 拦截器执行原理
5.1 DispatcherServlet
1、doDispatch:
源码节选:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
Exception dispatchException = null;
// 1.获取处理器执行链HandlerExecutionChain实例,从能处理请求的处理器映射HandlerMapping;
mappedHandler = getHandler(processedRequest);
// 2.获取该处理器对应的处理器适配器,用于执行处理器方法
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3.若处理器执行链的"应用预处理"方法返回false表明请求被拦截器链拦截,则终止该请求。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4. 若处理器执行链放行则执行处理器方法.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 5. 执行完处理器方法后,执行处理器执行链的"应用后置处理"方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 6.处理调用结果:若有异常把异常解析为modelAdnView然后渲染页面;
// 若无异常但处理器执行结果有modelAdnView返回则渲染页面;
// 若无异常无modelAdnView(比如返回Json)则打印日志;
// 最终都要执行处理器执行链的triggerAfterCompletion方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
//以上任何步骤异常都会终止然后跳到triggerAfterCompletion方法
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
2、processDispatchResult:
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);
}
}*/
// 渲染页面
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
//响应的不是"视图和模型"对象则打印日志如响应json
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
//最后倒序遍历拦截器链执行元素的AfterCompletion方法
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
5.2 HandlerExecutionChain
源码节选:
public class HandlerExecutionChain {
private final Object handler;//处理器
@Nullable
private HandlerInterceptor[] interceptors;//拦截器链
//获取处理器其
public Object getHandler() {
return this.handler;
}
1、applyPreHandle:
方法属于类HandlerExecutionChain;
源码节选:
//3.应用已注册拦截器的预处理方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();//3.1.获取拦截器链
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {//3.2.遍历拦截器
HandlerInterceptor interceptor = interceptors[i];
//3.3.若该拦截器的拦截方法拦截了请求(返回false)
if (!interceptor.preHandle(request, response, this.handler)) {
//则执行"AfterCompletion方法触发器"
triggerAfterCompletion(request, response, null);
return false;
}
//若放行则记录当前拦截器在拦截器链中的索引
//遇到拦截;AfterCompletion方法触发器会把该索引处及之前的放行拦截器的AfterCompletion执行
this.interceptorIndex = i;
}
}
return true;//无拦截器链或拦截器放行请求
}
2、triggerAfterCompletion:
方法属于类HandlerExecutionChain;
源码节选:
//3.3.AfterCompletion方法触发器
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//倒序遍历标记索引及之前的拦截器即已放行的拦截器
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
//执行拦截器的完成之后回调方法
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
3、applyPostHandle:
方法属于类HandlerExecutionChain;
源码节选:
//5.应用已注册拦截器的预处理方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
//获取拦截器链
HandlerInterceptor[] interceptors = getInterceptors();
//倒叙遍历所有拦截器
//并执行每个拦截器的postHandle方法
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
5.3 总结
doDispatch调用处理器执行链对象的applyPreHandle、applyPostHandle、triggerAfterCompletion方法可以遍历拦截器链执行拦截器内的方法;
若拦截器链的某个拦截器拦截了请求,则终止doDispatch,无法向下执行处理器方法,并遍历执行已放行拦截器的AfterCompletion方法;
若请求通过拦截器链,则在处理器适配器执行处理器完毕返回视图模型对象后,遍历执行拦截器链内拦截器的PostHandle方法;然后进入处理结果方法processDispatchResult来渲染异常视图或正常视图,没视图就打印日志,最后遍历执行拦截器链各元素的AfterCompletion方法。
外链图片转存失败,源站可能有防盗在这里插入!链机制,建描述https://im-blog.csdnimg.cn/img_convert/d6670793970a6ab199b07d311a888f5c.png)]
6 异常处理原理
默认情况下,Spring Boot提供/error处理所有错误的映射,流程:
执行处理器过程中被捕获的异常交给processDispatchResult方法处理,若方法内的异常解析器(含默认的两种以及自定义的异常解析器)能解析出非空ModelAndView则渲染响应,若方法内的异常解析器不能解析出非空视图则将异常以及异常解析器解析出的部分信息交由系统的/erro处理器处理;其中请求/erro处理器处理有两个途径:
(1)没有异常解析器可以解析出非空视图,异常被抛出,由系统捕获后触发response.sendError方法请求/erro处理器处理;
(2)由异常解析器直接调用response.sendError方法请求/erro处理器处理;
6.1 DispatcherServlet类
1、doDispatch方法:
源码节选:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
@Nullable
//系统的处理器异常解析器:
private List<HandlerExceptionResolver> handlerExceptionResolvers;
try{
ModelAndView mv = null;
Exception dispatchException = null;
//......
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
//捕获执行处理器过程中的异常
catch (Exception ex) {
dispatchException = ex;
}
//异常交给此方法处理,可以处理则渲染视图响应,否则把异常存进requst域后将异常抛出
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
//此方法是执行拦截链的完成之后方法,对捕获的异常又抛出;
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
//对于没被处理得异常(系统默认 handlerExceptionResolvers对异常不作处理)抛出交给系统作默认异常处理
}
2、processDispatchResult方法:
源码节选:
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);
}
}
//渲染视图
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
3、processHandlerException方法:
处理处理器异常方法:
源码节选:
@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
// Success and error responses may use different content types
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
// 将要返回的视图及模型对象
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
//则遍历处理器异常解析器处理异常,直至解析器返回非空的视图及模型对象才停止;
//若当前解析器可以处理该异常则返回视图及模型对象,否则返回null
//handlerExceptionResolvers组成元素:
//DefaultErrorAttributes异常解析器x1、HandlerExceptionResolverComposite复合异常解析器x1
//DefaultErrorAttributes异常解析器的解析方法返回null,同时将异常对象存进request域;
//HandlerExceptionResolverComposite复合异常解析器的解析方法返回null;
//所以系统默认的异常解析器返回的视图及模型对象为均为null;
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
//若视图及模型对象不为null返回之
if (exMv != null) {
//若视图及模型对象为空对象也返回null;
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
return exMv;
//若视图及模型对象为空则把不能处理的异常抛出去
throw ex;
}
6.2 HandlerExceptionResolver接口
异常解析器接口,只有一个异常解析方法;
@Nullable
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}
1、DefaultErrorAttributes类:
默认异常处理器的异常参数类:用于给默认异常处理器准备异常参数;
源码节选:
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
//将异常存进request域后返回null;不解析异常
storeErrorAttributes(request, ex);
return null;
}
private void storeErrorAttributes(HttpServletRequest request, Exception ex) {
request.setAttribute(ERROR_ATTRIBUTE, ex);
}
2、HandlerExceptionResolverComposite类:
处理器异常解析器组合类:
1、内部组合了ExceptionHandlerExceptionResolver异常处理异常解析器、
ResponseStatusExceptionResolver响应状态异常解析器、
DefaultHandlerExceptionResolver默认处理器异常解析器;
2、解析方法:遍历组合的解析器执行其解析方法,直至找到能处理异常并返回ModelAndview对象的解析器,若无解析器可以处理异常则返回null;
源码节选:
public class HandlerExceptionResolverComposite implements HandlerExceptionResolver, Ordered {
@Nullable
private List<HandlerExceptionResolver> resolvers;
@Override
@Nullable
public ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
if (this.resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
}
return null;
}
3、ExceptionHandlerExceptionResolver类:
1、自定义异常处理器异常解析类:标注了@ExceptionHandler({ArithmeticException.class,NullPointerException.class})的方法为自定义异常处理,
2、该解析器的解析方法做法是:跟据异常类型查找可以处理该异常的自定义异常解析器,找到则将异常交给他处理,若找不到则返回null;
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver{
implements ApplicationContextAware, InitializingBean {
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
}
}
4、ResponseStatusExceptionResolver类:
响应状态,异常解析类:
1、作用是解析标注在自定义异常上的@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="用户太多!")注解的
HttpStatus和reason信息(前提是该异常没有被自定义异常处理器处理),并通过response.sendError(statusCode, resolvedReason);
把这两异常信息转发请求/error处理器来处理;
源码节选:
public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware {
@Override
@Nullable
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
//获取注解@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="用户太多!")信息
ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
if (status != null) {
return resolveResponseStatus(status, request, response, handler, ex);
}
}
protected ModelAndView resolveResponseStatus(ResponseStatus responseStatus, HttpServletRequest request,
HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception {
int statusCode = responseStatus.code().value();
String reason = responseStatus.reason();
return applyStatusAndReason(statusCode, reason, response);
}
protected ModelAndView applyStatusAndReason(int statusCode, @Nullable String reason, HttpServletResponse response)
throws IOException {
response.sendError(statusCode, resolvedReason);
return new ModelAndView();
}
5、DefaultHandlerExceptionResolver类:
默认处理器异常解析器:用于处理框架底层异常比如MissingPathVariableException缺少路径变量异常等
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
@Override
@Nullable
protected ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
try {
if (ex instanceof HttpRequestMethodNotSupportedException) {
return handleHttpRequestMethodNotSupported(
(HttpRequestMethodNotSupportedException) ex, request, response, handler);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
return handleHttpMediaTypeNotSupported(
(HttpMediaTypeNotSupportedException) ex, request, response, handler);
}
//else if......
}
}