springmvc中HandlerMapping是干什么用的

server/2024/9/25 3:19:59/

HandlerMapping处理器映射器

作用是根据request找到相应的处理器Handler和Interceptors,然后封装成HandlerExecutionChain对象返回

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

实现类

HandlerMapping帮助DispatcherServlet进行web请求的url到具体处理类的匹配,用来根据请求的url查找Handler,内部维护的Map<String, Object>映射,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等

 private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
HanderMapping继承关系
HanderMapping继承关系

spring自带了多个处理器映射实现

  • BeanNameUrlHandlerMapping 根据控制器Bean的名字将控制器映射到URL
  • ControllerBeanNameHandlerMapping 与BeanNameUrlHandlerMapping类似
  • ControllerClassNameHandlerMapping 通过使用控制器的类名作为URL基础将控制器映射到URL
  • DefaultAnnotationHandlerMapping 将请求映射给使用@RequestMapping注解的控制器和控制器方法
  • SimplerUrlHandlerMapping 使用定义在Spring应用上下文的集合将控制器映射到URL
  • RequestMappingHandlerMapping SpringMVC3.1新增的,在springMVC3.1之前,DefaultAnnotationHandlerMapping会在类级别上选中一个控制器,然后通过AnnotationMethodHandlerAdapter定位到具体要调用的方法;而在SpringMVC3.1之后,这些操作全都放生在RequestMappingHandlerMapping中,从类级别和方法级别的@RequestMapping注解中获取到路径映射信息,使得在HandlerInterceptor中获取到的处理器肯定是一个HandlerMethod类型

配置

<!-- 开启注解 -->
<mvc:annotation-driven/>
<bean id="defaultAnnotationHandlerMapping"     class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
mvc:annotation-driven配置的作用
  • <mvc:annotation-driven/>会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdater、ExceptionHandlerExceptionResolver三个bean
  • 支持使用ConversionService实例对表单参数进行类型转换
  • 支持使用@NumberFormatannotation、@DataTimeFormat注解完成数据类型的格式化
  • 支持使用@Vaild注解对JavaBean实例进行JSR 303验证
  • 支持使用@RequestBody和@ResponseBody注解

RequestMappingHandlerMapping源码

由于一般都使用<mvc:annotation-driven/>进行配置,所以就以RequestMappingHandlerMapping为例进行讲解

创建

RequestMappingHandlerMapping实现了ApplicationContextAware接口,会执行setApplicationContext

// 调用链路 org.springframework.context.support.ApplicationObjectSupport#setApplicationContext ——>org.springframework.context.support.ApplicationObjectSupport#initApplicationContext(org.springframework.context.ApplicationContext) -->org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext
// org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext
protected void initApplicationContext() throws BeansException {
  // 扩展interceptors的方法,空实现
   extendInterceptors(this.interceptors);
  // 将容器中的所有MappedInterceptor类型的bean添加到mappedInterceptors中
   detectMappedInterceptors(this.adaptedInterceptors);
  // 初始化Interceptor,将interceptors中的对象添加到adaptedInterceptors中
   initInterceptors();
}

RequestMappingHandlerMapping实现了InitializingBean接口,会执行afterPropertiesSet

// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet
public void afterPropertiesSet() {
   initHandlerMethods();
}
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods
protected void initHandlerMethods() {
  // 拿到容器中的bean,筛选出Handler
  String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
    BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
    getApplicationContext().getBeanNamesForType(Object.class))
;

  for (String beanName : beanNames) {
   if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
    Class<?> beanType = null;
    try {
     beanType = getApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
     
    }
        // (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));  判断
    if (beanType != null && isHandler(beanType)) {
          // 将访问地址、Method进行映射
     detectHandlerMethods(beanName);
    }
   }
  }
  handlerMethodsInitialized(getHandlerMethods());
 }
访问

在进行访问的时候会通过org.springframework.web.servlet.DispatcherServlet#getHandler方法来遍历handlerMappings

HandlerExecutionChain handler = hm.getHandler(request);

来调用HandlerMapping的getHandler方法

// org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  // 找到Handler,根据地址找到对应的方法
   Object handler = getHandlerInternal(request);
   if (handler == null) {
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
  // 如果找到的handler是一个字符串,可能是beanName,从bean容器中查找
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = getApplicationContext().getBean(handlerName);
   }

  // 为handler生成执行链,即为HandlerExecutionChain对象添加interceptor
   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;
}
getHandlerInternal
// org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   
   this.mappingRegistry.acquireReadLock();
   try {
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
      this.mappingRegistry.releaseReadLock();
   }
}
getHandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
   for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
      if (interceptor instanceof MappedInterceptor) {
         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
         if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
            chain.addInterceptor(mappedInterceptor.getInterceptor());
         }
      }
      else {
         chain.addInterceptor(interceptor);
      }
   }
   return chain;
}

https://zhhll.icu/2021/框架/springmvc/底层剖析/2.HandlerMapping/

本文由 mdnice 多平台发布


http://www.ppmy.cn/server/42860.html

相关文章

Rust 赋能前端 -- 写一个 File 转 Img 的功能

所有耀眼的成绩,都需要苦熬,熬得过,出众;熬不过,出局 大家好,我是柒八九。一个专注于前端开发技术/Rust及AI应用知识分享的Coder 此篇文章所涉及到的技术有 Rustwasm-bindgen/js-sys/web-sysWeb WorkerWebAssemblyWebpack/Vite配置WebAssemblyOffscreenCanvas脚手架生成项…

PHP质量工具系列之php_CodeSniffer

PHP_CodeSniffer 是一组两个 PHP 脚本&#xff1a;主脚本 phpcs 对 PHP、JavaScript 和 CSS 文件进行标记&#xff0c;以检测是否违反定义的编码标准&#xff1b;第二个脚本 phpcbf 自动纠正违反编码标准的行为。PHP_CodeSniffer 是一个重要的开发工具&#xff0c;可以确保你的…

【Linux】LAMP集群分布式安全方案

LAMP集群分布式安全方案主要涉及确保Linux、Apache、MySQL和PHP&#xff08;LAMP&#xff09;组合构成的集群环境的安全性和稳定性。 本次实验通过网络层安全对防火墙配置&#xff1a;使用防火墙&#xff08;如iptables或firewalld&#xff09;来限制对集群的访问&#xff0c;只…

Unity vscode在mac上的编译环境设置

在settings.json文件中配置以下信息。 settings.json路径一般在/Users/xxx/Library/Application Support/Code/User/settings.json {"omnisharp.useGlobalMono": "always","editor.fontLigatures": false,"omnisharp.useModernNet": …

算法打卡 Day9(字符串KMP 算法)-实现 strStr+ 重复的子字符串

KMP 算法 KMP 算法解决的是字符串匹配的问题&#xff0c;其经典思想是&#xff1a;当出现的字符串不匹配时&#xff0c;可以记录一部分之前已经匹配的文本内容&#xff0c;利用这些信息避免从头再去做匹配。 前缀表 next 数组就是一个前缀表。前缀表是用来回退的&#xff0c…

自然资源-中华人民共和国土地管理法实施条例(2021年修订)

中华人民共和国土地管理法实施条例&#xff08;2021年修订&#xff09; 中华人民共和国土地管理法实施条例 &#xff08;1998年12月27日中华人民共和国国务院令第256号发布 根据2011年1月8日《国务院关于废止和修改部分行政法规的决定》第一次修订 根据2014年7月29日《国务院…

c++11 标准模板(STL)本地化库 - 平面类别(std::numpunct_byname) 表示系统提供的具名本地环境的 std::numpunct

本地化库 本地环境设施包含字符分类和字符串校对、数值、货币及日期/时间格式化和分析&#xff0c;以及消息取得的国际化支持。本地环境设置控制流 I/O 、正则表达式库和 C 标准库的其他组件的行为。 平面类别 表示系统提供的具名本地环境的 std::numpunct std::numpunct_byn…

逻辑回归模型的背景与应用

1.1逻辑回归模型的背景与应用 逻辑回归模型&#xff0c;作为一种经典的机器学习方法&#xff0c;起源于统计学领域。在众多实际应用场景中&#xff0c;逻辑回归模型都发挥着重要作用&#xff0c;尤其在分类问题中。当我们需要对具有离散特征的数据进行建模和预测时&#xff0c…