每个handlerMapping包含一系列url到Controller的映射。

1、类层次结构

2、SimpleUrlHandlerMapping的处理流程

该类中用urlMap来存储映射关系。HandlerMapping接口中定义了getHandler方法,可以获取到请求对应的HandlerExecutionChain,当中封装了具体的Controller对象。HandlerExecutionChain包含了Intercepter链和一个handler。通过这个拦截链,可以实现对handler的增强。SimpleUrlHandlerMapping主要是注册url和对应的handler,是通过其基类AbstractUrlHandlerMapping来注册的,其注册代码如下

public void initApplicationContext() throws BeansException {super.initApplicationContext();registerHandlers(this.urlMap);
}protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {if (urlMap.isEmpty()) {logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");}else {urlMap.forEach((url, handler) -> {// Prepend with slash if not already present.if (!url.startsWith("/")) {url = "/" + url;}// Remove whitespace from handler bean name.if (handler instanceof String) {handler = ((String) handler).trim();}registerHandler(url, handler);});}
}//AbstractUrlHandlerMapping类中的注册
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {Assert.notNull(urlPath, "URL path must not be null");Assert.notNull(handler, "Handler object must not be null");Object resolvedHandler = handler;// Eagerly resolve handler if referencing singleton via name.if (!this.lazyInitHandlers && handler instanceof String) {String handlerName = (String) handler;ApplicationContext applicationContext = obtainApplicationContext();if (applicationContext.isSingleton(handlerName)) {resolvedHandler = applicationContext.getBean(handlerName);}}Object mappedHandler = this.handlerMap.get(urlPath);if (mappedHandler != null) {if (mappedHandler != resolvedHandler) {throw new IllegalStateException("Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");}}else {if (urlPath.equals("/")) {if (logger.isInfoEnabled()) {logger.info("Root mapping to " + getHandlerDescription(handler));}setRootHandler(resolvedHandler);}else if (urlPath.equals("/*")) {if (logger.isInfoEnabled()) {logger.info("Default mapping to " + getHandlerDescription(handler));}setDefaultHandler(resolvedHandler);}else {this.handlerMap.put(urlPath, resolvedHandler);if (logger.isInfoEnabled()) {logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));}}}
}

3、handlerMapping对请求的映射处理

首先根据初始化时的handlerMapping映射关系,在AbstractHandlerMapping中调用getHandler得到DispatcherServlete需要的HandlerExecutionChain.在构建HandlerExecutionChain时先要获取handler,是在子类AbstractUrlHandlerMapping的getHandlerInternal获取得到,主要根据请求构建url路径,然后在handlerMap中查找得到对应的handler。查找分下面几种情况

(1)在handlerMap中可以找到,如果是字符串,则通过名字找到bean,接着构造HandlerExecutionChain

(2)在handlerMap中可以找不到,说明handlerMap中的key是带有模式的,则在这些模式中作匹配

(3)上面两种情况都没有找到handler,则使用rootHandler或者defaultHandler,以此来构造HandlerExecutionChain

//AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {Object handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);if (CorsUtils.isCorsRequest(request)) {CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;
}//AbstractUrlHandlerMapping
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);Object handler = lookupHandler(lookupPath, request);if (handler == null) {// We need to care for the default handler directly, since we need to// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.Object rawHandler = null;if ("/".equals(lookupPath)) {rawHandler = getRootHandler();}if (rawHandler == null) {rawHandler = getDefaultHandler();}if (rawHandler != null) {// Bean name or resolved handler?if (rawHandler instanceof String) {String handlerName = (String) rawHandler;rawHandler = obtainApplicationContext().getBean(handlerName);}validateHandler(rawHandler, request);handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);}}if (handler != null && logger.isDebugEnabled()) {logger.debug("Mapping [" + lookupPath + "] to " + handler);}else if (handler == null && logger.isTraceEnabled()) {logger.trace("No handler mapping found for [" + lookupPath + "]");}return handler;
}protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {// Direct match?Object handler = this.handlerMap.get(urlPath);if (handler != null) {// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}validateHandler(handler, request);return buildPathExposingHandler(handler, urlPath, urlPath, null);}// Pattern match?List<String> matchingPatterns = new ArrayList<>();for (String registeredPattern : this.handlerMap.keySet()) {if (getPathMatcher().match(registeredPattern, urlPath)) {matchingPatterns.add(registeredPattern);}else if (useTrailingSlashMatch()) {if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {matchingPatterns.add(registeredPattern +"/");}}}String bestMatch = null;Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);if (!matchingPatterns.isEmpty()) {matchingPatterns.sort(patternComparator);if (logger.isDebugEnabled()) {logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);}bestMatch = matchingPatterns.get(0);}if (bestMatch != null) {handler = this.handlerMap.get(bestMatch);if (handler == null) {if (bestMatch.endsWith("/")) {handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));}if (handler == null) {throw new IllegalStateException("Could not find handler for best pattern match [" + bestMatch + "]");}}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}validateHandler(handler, request);String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);// There might be multiple 'best patterns', let's make sure we have the correct URI template variables// for all of themMap<String, String> uriTemplateVariables = new LinkedHashMap<>();for (String matchingPattern : matchingPatterns) {if (patternComparator.compare(bestMatch, matchingPattern) == 0) {Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);uriTemplateVariables.putAll(decodedVars);}}if (logger.isDebugEnabled()) {logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);}return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);}// No handler found...return null;
}

3、DispatcherServlet对http请求的分发处理

首先检查checkMultipart,然后在遍历handerMapping中根据请求得到HandlerExecutionChain,只要有一个满足就可以。获取HandlerAdapter,执行拦截器的前置处理,执行HandlerAdapter,拦截器的后置处理。对结果作视图渲染,执行拦截器的完成处理。

其时序图如下

相关代码如下

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 {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// Determine handler for the current request.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 (logger.isDebugEnabled()) {logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);}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 afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
}protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping hm : this.handlerMappings) {if (logger.isTraceEnabled()) {logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");}HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}}return null;
}protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {for (HandlerAdapter ha : this.handlerAdapters) {if (logger.isTraceEnabled()) {logger.trace("Testing handler adapter [" + ha + "]");}if (ha.supports(handler)) {return ha;}}}throw new ServletException("No adapter for handler [" + handler +"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

Spring MVC中handlerMapping的设计相关推荐

  1. spring mvc中filter的设计与实现

    抽象类 GenericFilterBean:是javax.servlet.Filter的简单基本实现,将配置参数init-param(web.xml中的fitler标签的)作为bean属性 OnceP ...

  2. Spring MVC中的二三事

    HandlerMapping和HandlerAdapter 这个两个组件应该算是spring mvc中最重要的几个组件之一了,当一个请求到达DispatcherSerlvet后,spring mvc就 ...

  3. 在Spring MVC中使用Apache Shiro安全框架

    我们在这里将对一个集成了Spring MVC+Hibernate+Apache Shiro的项目进行了一个简单说明.这个项目将展示如何在Spring MVC 中使用Apache Shiro来构建我们的 ...

  4. Spring MVC中Session的正确用法之我见02

    Spring MVC中Session的正确用法之我见 Spring MVC是个非常优秀的框架,其优秀之处继承自Spring本身依赖注入(Dependency Injection)的强大的模块化和可配置 ...

  5. Spring MVC中的视图解析ViewResolver

    http://blog.csdn.net/prince2270/article/details/5891085 在Spring MVC中,当Controller将请求处理结果放入到ModelAndVi ...

  6. Spring MVC 中的基于注解的 Controller

    为什么80%的码农都做不了架构师?>>>    Spring MVC 中的基于注解的 Controller @Controller 基于注解的 Controller   终于来到了基 ...

  7. 11月30在spring mvc中使用Validator框架和文件上传

    首先回顾了spring mvc中的表单验证和业务逻辑校验失败后,回到表单页面中显示错误信息的整个内部运行流程. 表单校验出错后回到表单注册页面是由默认的SimpleFormController的pro ...

  8. spring mvc 异步_DeferredResult – Spring MVC中的异步处理

    spring mvc 异步 DeferredResult是一个可能尚未完成的计算的容器,它将在将来提供. Spring MVC使用它来表示异步计算,并利用Servlet 3.0 AsyncContex ...

  9. DeferredResult – Spring MVC中的异步处理

    DeferredResult是一个可能尚未完成的计算的容器,它将在将来提供. Spring MVC使用它来表示异步计算,并利用Servlet 3.0 AsyncContext异步请求处理. 简要介绍一 ...

最新文章

  1. python三维图-python 三维坐标图
  2. QT官方第三方开源工具
  3. C#封装WebBrowser时NewWindow事件无法获取Url的解决方法
  4. SAP CRM和Cloud for Customer的数据同步一例
  5. 竞价排名才是万恶之源
  6. android打开视频噔_Android、iOS不可错过!10款堪称神器的高质量APP,请低调使用...
  7. 分享2个Python处理Excel的脚本
  8. mysql数据库怎么md5加密解密_mysql数据库中md5加密解密
  9. APP登录界面UI设计欣赏
  10. RGB 透明度 对应代码
  11. 2022AcWing寒假算法每日一题之1934. 贝茜放慢脚步
  12. WinEdit初使用
  13. windows操作系统---1
  14. C++知三角形三边求面积
  15. linux中项目常用的start.sh和stop.sh
  16. 个人能力知识体系如何构建?
  17. 浅谈MES的通用设计之一:数据传输
  18. 有什么免费照片换发型软件?推荐几个换发型软件给你
  19. iOS有反检测能力的越狱工具shadow的分析和检测
  20. JAVA伏魔_伏魔三国志2-转轮圣王篇

热门文章

  1. 新建用户组、用户、用户密码、删除用户组、用户(适合CentOS、Ubuntu系统)
  2. 获取文件夹所占空间的大小
  3. 如何对SQL Server数据库中的孤立用户和系统及用户建立映射
  4. 苹果设置网易邮箱收件服务器,如何在iPhone 3/4、iPod touch的邮件应用程序中使用IMAP服务...
  5. HTML产品表单列表,HTML表格、列表、表单
  6. 微服务认证模式_微服务之“网关模式”
  7. python安装教程win10-PyCharm 安装教程(Windows)
  8. python 调用linux命令-Python调用shell命令常用方法
  9. python下载教程win10-win10系统下如何安装Python软件
  10. 怎么安装python3-Ubuntu16.04怎样安装Python3.6