5.1 前端控制器 DispatcherServlet
继承结构:
前端请求进来,会执行FrameworkServlet的doGet/doPost方法,而doGet/doPost方法都会执行processRequest(request,response)方法,processRequest()主要做的事情有:
- 获取到上一个请求保存的LocaleContext,建立新的LocaleContext
- 获取到上一个请求保存的RequestAttributes,建立新的RequestAttributes
调用抽象方法doService(),此方法由继承该类的DispatcherServlet类来实现
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;// 获取到上一个请求保存的LocaleContextLocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();// 建立新的LocaleContextLocaleContext localeContext = buildLocaleContext(request);// 获取到上一个请求保存的RequestAttributesRequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();// 建立新的RequestAttributesServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());// 新的RequestAttributes绑定到LocalThreadinitContextHolders(request, localeContext, requestAttributes);try {doService(request, response);}catch (ServletException | IOException ex) {failureCause = ex;throw ex;}catch (Throwable ex) {failureCause = ex;throw new NestedServletException("Request processing failed", ex);}finally {resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) {requestAttributes.requestCompleted();}logResult(request, response, failureCause, asyncManager);publishRequestHandledEvent(request, response, startTime, failureCause);}}
DisapatcherServlet类的doService方法主要做的事情:
- 获取请求域中的属性名存起来做个副本
- 往request设置一些属性值使框架对象可用于处理程序和视图对象
- flashMapManager管理重定向参数携带
执行doDispatcher()方法
@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {logRequest(request);// Keep a snapshot of the request attributes in case of an include,// to be able to restore the original attributes after the include.Map<String, Object> attributesSnapshot = null;if (WebUtils.isIncludeRequest(request)) {attributesSnapshot = new HashMap<>();// 获取请求域中的属性名存起来做个副本Enumeration<?> attrNames = request.getAttributeNames();while (attrNames.hasMoreElements()) {String attrName = (String) attrNames.nextElement();if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {attributesSnapshot.put(attrName, request.getAttribute(attrName));}}}// 往request设置一些属性值使框架对象可用于处理程序和视图对象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());// flashMapManager管理重定向参数携带if (this.flashMapManager != null) {FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);if (inputFlashMap != null) {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);}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);}}}}
5.2 核心方法doDisapatcher()分析
该方法是SpringMVC的核心方法,具体做的事情如下:
- 1. 检查是否文件上传的请求
- 2. 取得当前请求的Controller,也称为Handler,即处理器。这里并不是直接返回Controller,而是返 回HandlerExecutionChain请求处理链对象,该对象封装了Handler和Interceptor。如果handler为空则返回404。
- 3 .获取处理请求的处理器适配器HandlerAdapter,处理last-modified请求头。
- 4. 实际处理器处理请求,返回结果视图对象ModelAndView,结果视图对象处理
- 5. 最终会调用HandlerInterceptor的afterCompletion方法 ```java protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try { ModelAndView mv = null; Exception dispatchException = null;
try {
// 1.检查是否文件上传的请求processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// Determine handler for the current request./*** 2.取得当前请求的Controller,也称为Handler,即处理器* 这里并不是直接返回Controller,而是返回HandlerExecutionChain请求处理链对象* 该对象封装了Handler和Interceptor*/mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {// 如果handler为空则返回404noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.// 3.获取处理请求的处理器适配器HandlerAdapterHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.// 处理last-modified请求头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.// 4. 实际处理器处理请求,返回结果视图对象ModelAndViewmv = 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) { // 最终会调用HandlerInterceptor的afterCompletion方法 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 afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}
} else {
// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}
5.3 SpringMVC的核心步骤
调⽤getHandler()获取到能够处理当前请求的执⾏链 HandlerExecutionChain(Handler+拦截器)
- 调⽤getHandlerAdapter();获取能够执⾏1)中Handler的适配器
- 适配器调⽤Handler执⾏ha.handle(总会返回⼀个ModelAndView对象)
调⽤processDispatchResult()⽅法完成视图渲染跳转
5.3.1 getHandler方法分析
@Nullableprotected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// 遍历handlerMappings,里面有两个HandlerMapping的实现类// 分别是BeanNameUrlHandlerMapping和RequestMappingHandlerMappingif (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {// 容器初始化的时候通过扫描注解,配置了url和handler的关系HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {// 返回的HandlerExecutionChain包含了Handler和Interceptor信息return handler;}}}return null;}
5.3.2 getHandlerAdapter方法分析
// 通过Handler匹配到支持的Adapter适配器protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {/*** HandlerAdapter的三个实现类 判断支持那个然后返回* 1.HttpRequestHandlerAdapter* 2.SimpleControllerHandlerAdapter* 3.RequestMappingHandlerAdapter*/for (HandlerAdapter adapter : this.handlerAdapters) {if (adapter.supports(handler)) {return adapter;}}}throw new ServletException("No adapter for handler [" + handler +"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");}
5.3.3 适配器调⽤Handler执⾏ha.handle()方法
mav.invokeHandlerMethod(request,response,handlerMethod)
- 对handlerMethod进行参数等的适配处理,并调用目标handler
- 对请求参数进行处理,调用目标HanderMethod,并且将返回值封装成MethodAndView对象
- 对目标handler的参数进行处理,并且调用目标handler
- 将request中参数转换成当前handler的参数形式
- doInvole()方法主要结合处理后的参数,使用反射对目标方法进行调用
5.3.4 processDispatchResult()完成视图渲染跳转
```java private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
// Did the handler return a view to render? if (mv != null && !mv.wasCleared()) {@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {
}// 是否处理返回渲染的视图render(mv, request, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) { View view; String viewName = mv.getViewName(); if (viewName != null) { // We need to resolve the view name. // 解析封装视图 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException(“Could not resolve view with name ‘“ + mv.getViewName() + “‘ in servlet with name ‘“ + getServletName() + “‘“); } } }
protected View resolveViewName(String viewName, @Nullable Map
```java// 在解析出View视图对象的过程中会判断是否重定向、是否转发等,不同的情况封装的是不同的// View实现@Overrideprotected View createView(String viewName, Locale locale) throws Exception {// If this resolver is not supposed to handle the given view,// return null to pass on to the next resolver in the chain.if (!canHandle(viewName, locale)) {return null;}// Check for special "redirect:" prefix.if (viewName.startsWith(REDIRECT_URL_PREFIX)) {String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());RedirectView view = new RedirectView(redirectUrl,isRedirectContextRelative(), isRedirectHttp10Compatible());String[] hosts = getRedirectHosts();if (hosts != null) {view.setHosts(hosts);}return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);}// Check for special "forward:" prefix.if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());InternalResourceView view = new InternalResourceView(forwardUrl);return applyLifecycleMethods(FORWARD_URL_PREFIX, view);}// Else fall back to superclass implementation: calling loadView.return super.createView(viewName, locale);}
@Overridepublic void render(@Nullable Map<String, ?> model, HttpServletRequest request,HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {logger.debug("View " + formatViewName() +", model " + (model != null ? model : Collections.emptyMap()) +(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));}Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);prepareResponse(request, response);// 把modelMap中的数据暴露到request请求域中// 这也是后台model.add后视图可以从请求域中取出的原因renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);}
5.4 MVC九大组件分析
- MVC的九大组件在DispatcherServlet类中都有定义。 ```java /* MultipartResolver used by this servlet. / // 多部件解析器 @Nullable private MultipartResolver multipartResolver;
/* LocaleResolver used by this servlet. / // 区域化 国际化解析器 @Nullable private LocaleResolver localeResolver;
/* ThemeResolver used by this servlet. / // 主题解析器 @Nullable private ThemeResolver themeResolver;
/* List of HandlerMappings used by this servlet. /
// 处理器映射器组件
@Nullable
private List
/* List of HandlerAdapters used by this servlet. /
// 处理器适配器组件
@Nullable
private List
/* List of HandlerExceptionResolvers used by this servlet. /
// 异常解析器组件
@Nullable
private List
/* RequestToViewNameTranslator used by this servlet. / // 默认视图名转换器组件 @Nullable private RequestToViewNameTranslator viewNameTranslator;
/* FlashMapManager used by this servlet. / // flash属性管理组件 重定向属性 @Nullable private FlashMapManager flashMapManager;
/* List of ViewResolvers used by this servlet. /
// 视图解析器
@Nullable
private List
2. 九⼤组件都是定义了接⼝,接⼝其实就是定义了该组件的规范,⽐如ViewResolver、HandlerAdapter等都是接⼝3. 九大组件初始化入口```java@Overrideprotected void onRefresh(ApplicationContext context) {// 初始化策略initStrategies(context);}protected void initStrategies(ApplicationContext context) {// 初始化多文件上传组件initMultipartResolver(context);// 初始化本地语言环境initLocaleResolver(context);// 初始化主题模板处理器initThemeResolver(context);// 初始化处理器映射器initHandlerMappings(context);// 初始化处理器适配器initHandlerAdapters(context);// 初始化异常拦截器initHandlerExceptionResolvers(context);// 初始化视图预处理器initRequestToViewNameTranslator(context);// 初始化视图转换器initViewResolvers(context);// 初始化FlashMap管理器initFlashMapManager(context);}
解析initHandlerMappings:如果按照类型和按照固定id从ioc容器中找不到对应组件,则会按照默认策略进⾏注册初始化,默认策略在DispatcherServlet.properties⽂件中配置
private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// 按照HandlerMapping.class类型去ioc容器中找到所有的HandlerMappingMap<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}else {try {// 否则在ioc中按照固定名称id(handlerMapping)去查找HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);this.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}// 最后还为控则按照默认策略生成(按照默认方式实例化生成HandlerMapping)if (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerMappings declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}
