protected final void processRequest(HttpServletRequest request, HttpServletResponse response){
// 处理多言语问题
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
// 创建RequestAttributes对象,整个请求通用,封装了请求和响应对象
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
// 里面设置属性都是调用request对象设置属性,所以,整个请求需要获取request对象使用RequestContextHolder就能获取
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
// 获取异步请求管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// 添加一个拦截器,负责处理requestAttributes
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// 初始化RequestContextHolder,将requestAttributes保存到RequestContextHolder中
initContextHolders(request, localeContext, requestAttributes);{
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
}
// 处理请求
doService(request, response);{
// 把当前web容器和其他组件放入请求域中
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
// flush管理器,用于重定向存储数据的管理器
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// 校验是不是文件上传请求,如果是,返回新的request对象
HttpServletRequest processedRequest = checkMultipart(request);{
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
// 使用文件解析器解析请求,返回新的request对象
return this.multipartResolver.resolveMultipart(request);
}
}
// 找到的handler和拦截器封装成HandlerExecutionChain对象
HandlerExecutionChain mappedHandler = getHandler(processedRequest);{
// 从所有的HandlerMapping中找
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);{
// 获取对应的handler,具体的逻辑在对应的handlerMapping中,可以看HandlerMapping的获取Handler方法
Object handler = getHandlerInternal(request);
// 将handler封装成HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);{
创建HandlerExecutionChain对象返回
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 将存在HandlerMapping中的拦截器附加到Handler中,形成拦截器链
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 如果不是,直接添加
if (!(interceptor instanceof MappedInterceptor) {
chain.addInterceptor(interceptor);
return chain;
}
// 如果是自定义,设置了条件的拦截器,要特殊处理下
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// 该拦截器还要匹配拦截当前请求
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
}
if (handler != null) {
return handler;
}
}
}
}
// 未找到Handler,直接响应404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);{
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
return;
}
// 查找handlerAdapter,HandlerAdapter才是真正执行业务逻辑的类
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());{
// 遍历所有的HandlerAdapter
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler){
// 能处理请求的HandlerAdapter
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
return handler instanceof HandlerFunction;
return (handler instanceof HttpRequestHandler);
return (handler instanceof Controller);
return (handler instanceof Servlet);
}) {
return adapter;
}
}
}
}
// 执行handler的前置方法
if (!mappedHandler.applyPreHandle(processedRequest, response){
// 遍历所有的拦截器,
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
// 执行拦截器的前置方法
if (!interceptor.preHandle(request, response, this.handler)) {
// 如果前置方法返回false
// 直接执行请求处理结束的方法
triggerAfterCompletion(request, response, null);
// 请求结束
return false;
}
this.interceptorIndex = i;
}
// 当返回true表示所有的拦截器前置方法都返回了ture
return true;
})
{
// 如果前置方法返回false,当前请求结束
return;
}
// 执行目标方法,无论如何都会返回一个ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());{
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal{
// 校验请求是否可以处理
checkRequest(request);{
String method = request.getMethod();
// 如果设置了限制的请求方式,但是当前请求不符合规则
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
}
// 如果设置了请求必须要有session
if (this.requireSession && request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
// 如果同一个session需要同步执行,则需要对session加锁
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
// 使用session最为锁对象
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
// 加锁执行方法
ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
}else{
// 不需要同步就直接执行目标方法,详请看笔记执行目标方法原理
ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 如果当前请求不包含Cache-Control请求头,
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
// 如果handlerMethod存在一些Session缓存,就需要缓存一些会话信息
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);{
// 例如设置过期时间
if cacheSeconds>0 response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis() + seconds * 1000L);
else response.setHeader(HEADER_PRAGMA, "no-cache");
}
}
else {
// 预处理设置响应头
prepareResponse(response);{
// 根据不同条件设置
applyCacheControl(response, this.cacheControl);
applyCacheSeconds(response, this.cacheSeconds);
response.addHeader("Vary", value);
}
}
}
return mav;
}
}
// 如果请求被异步启动了,就不处理了
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 获取视图名,如果没有设置视图名,返回一个默认的视图名,就是url对应的字符串当做视图
applyDefaultViewName(processedRequest, mv);{
// 如果没有异常,并且modeAndView中没有设置视图
// 在Controller的方法中,没有添加ResponseBody注解,也没有添加String返回值,也没有使用Response响应
// 此时springmvc默认会返回一个空的modeAndView,符合这个条件
// 例如: @GetMapping("haha") public void haha(HttpServletRequest req) { req.setAttribute("luck", "luck");}
// 视图名会被解析成haha,因为不管有没有返回值,都会返回一个ModelAndView
// 大胆猜测,如果我的方法返回void,然后将设置属性到request,或者model中,然后SpringMVC会自动跳转到路径对应的jsp页面
// 也就是haha.jsp中,这个时候,在jsp中${luck}是可以获取到值的
if (mv != null && !mv.hasView()) {
// 获取一个默认的视图名,就是url对应的字符串当做视图
String defaultViewName = getDefaultViewName(request);
// 将这个当做是视图名,到时候找对应文件渲染
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
// 执行所有的拦截器后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
catch (Exception ex) Exception dispatchException = ex;
catch (Throwable err) Exception dispatchException = new NestedServletException("Handler dispatch failed", err);;
// 处理相应结果,视图渲染,包括正常渲染和异常渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);{
boolean errorView = false;
// 判断是否有异常,如果有异常,就要构造异常的modeAndView,如果没有异常,那就直接渲染
if (exception != null) {
// 返回异常为ModelAndViewDefiningException,返回此异常的ModeAndView
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
// 如果是其他类型的异常
else {
// 获取处理请求的handler
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 构建一个异常的ModeAndView,处理异常
mv = processHandlerException(request, response, handler, exception);{
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
// 如果存在异常解析器
if (this.handlerExceptionResolvers != null) {
// 遍历所有的异常解析器解析异常
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
// 使用异常解析器解析异常,详情见异常解析器处理加载处理原理
ModelAndView exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
// 解析到异常的ModelAndView对象
if (exMv != null) {
// 如果这个ModelAndView是一个空的对象,也就是不包含响应视图等等,返回空
// exMv.isEmpty 源码 return (this.view == null && CollectionUtils.isEmpty(this.model));
// 表示当前view为空,并且Model modelMap也为空
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// 如果View为空的情况下,但是Model modelMap不为空的情况下,会使用路径作为默认的视图界面
// 因为model中有数据,可以直接将model中的数据传递都页面中,详情见上面的applyDefaultViewName(processedRequest, mv);方法
// 例如: @GetMapping("haha") public void haha(HttpServletRequest req) { req.setAttribute("luck", "luck");}
// 视图名会被解析成haha,因为不管有没有返回值,都会返回一个ModelAndView
// 大胆猜测,如果我的方法返回void,然后将设置属性到request,或者model中,然后SpringMVC会自动跳转到路径对应的jsp页面
// 也就是haha.jsp中,这个时候,在jsp中${luck}是可以获取到值的
// 例如: @ExceptionHandler(NullPointerException.class) public void e(Model model) {model.addAttribute("luck", "luck");}
if (!exMv.hasView()) {
// 获取默认的View的视图名
String defaultViewName = getDefaultViewName(request);
// 如果设置了视图名,那么就要按正常的视图渲染流程
if (defaultViewName != null) {
exMv.setViewName(defaultViewName);
}
}
// 将一个异常相关的属性数据存入request域中
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
}
// 异常视图标志
errorView = (mv != null);
}
}
// modeAndView的wasCleared默认为false,除非手动调用了mv.clear
if (mv != null && !mv.wasCleared()) {
// 会进入视图渲染,详情见视图渲染原理
render(mv, request, response);
// 如果处理了异常的情况下,请求放在请求域中的异常数据都清除
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
// 如果是异步请求,直接结束,不执行下面的拦截器后置方法
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
// 找到了handler,执行拦截器的后置方法
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
// 整个请求结束,无论如何到需要执行拦截器的afterCompletion方法
catch (Exception ex) triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
catch (Throwable err) triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));
// doDispatch执行结束,如果是文件上传,需要删除临时文件
finally if (multipartRequestParsed) cleanupMultipart(processedRequest);{
if (this.multipartResolver != null) {
// 调用文件解析器,清理文件,因为文件上传之前,会创建临时文件在磁盘中,请求处理完成要删除
this.multipartResolver.cleanupMultipart(multipartRequest);
}
}
}
}
// 重置requestAttributes
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
// 发布事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}