Spring-mvc-MappingRegistry

简介: 《读尽源码》
  • 源码路径: org.springframework.jms.annotation.EnableJms
  • 类全路径
  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry
  • 基本属性
class MappingRegistry {
   /**
    * key:mapping
    * value: mapping registration
    */
   private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
   /**
    * key: mapping
    * value: handlerMethod
    */
   private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
   /**
    * key: url
    * value: list mapping
    */
   private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
   /**
    * key: name
    * value: handler method
    */
   private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
   /**
    * key:handler method
    * value: 跨域配置
    */
   private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
   /**
    * 读写锁
    */
   private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
}Copy to clipboardErrorCopied
  • 写一个简单的 controller 来进行解析
@RestController
@RequestMapping("/demo")
public class DemoController {
   @GetMapping("/do")
   public Object go() {
      return "fff";
   }
}Copy to clipboardErrorCopied
  • 前置链路追踪
  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#registerHandlerMethod
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
    super.registerHandlerMethod(handler, method, mapping);
    this.updateConsumesCondition(mapping, method);
}Copy to clipboardErrorCopied
  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
}Copy to clipboardErrorCopied
  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register
    本文重点的方法

createHandlerMethod

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
   // 是否是字符串
   if (handler instanceof String) {
      // 创建对象
      return new HandlerMethod((String) handler,
            obtainApplicationContext().getAutowireCapableBeanFactory(), method);
   }
   return new HandlerMethod(handler, method);
}Copy to clipboardErrorCopied
  • HandlerMethod 构造函数
public HandlerMethod(String beanName, BeanFactory beanFactory, Method method){}
public HandlerMethod(Object bean, Method method) {}Copy to clipboardErrorCopied

HandlerMethod

  • 成员变量
public class HandlerMethod {
   /** Logger that is available to subclasses. */
   protected final Log logger = LogFactory.getLog(getClass());
   /**
    * beanName 或者 bean 实例
    */
   private final Object bean;
   /**
    * 上下文
    */
   @Nullable
   private final BeanFactory beanFactory;
   /**
    * bean 类型
    */
   private final Class<?> beanType;
   /**
    * 处理方法
    */
   private final Method method;
   private final Method bridgedMethod;
   /**
    * 方法参数
    */
   private final MethodParameter[] parameters;
}Copy to clipboardErrorCopied

validateMethodMapping

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#validateMethodMapping

HandlerMethod 进行验证

private void validateMethodMapping(HandlerMethod handlerMethod, T mapping) {
   // Assert that the supplied mapping is unique.
   // 从缓存中获取
   HandlerMethod existingHandlerMethod = this.mappingLookup.get(mapping);
   // 是否为空 , 是否相同
   if (existingHandlerMethod != null && !existingHandlerMethod.equals(handlerMethod)) {
      throw new IllegalStateException(
            "Ambiguous mapping. Cannot map '" + handlerMethod.getBean() + "' method \n" +
                  handlerMethod + "\nto " + mapping + ": There is already '" +
                  existingHandlerMethod.getBean() + "' bean method\n" + existingHandlerMethod + " mapped.");
   }
}Copy to clipboardErrorCopied

getDirectUrls

  • 找到 mapping 匹配的 url
  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#getDirectUrls
private List<String> getDirectUrls(T mapping) {
   List<String> urls = new ArrayList<>(1);
   // mapping.getPatternsCondition().getPatterns()
   for (String path : getMappingPathPatterns(mapping)) {
      // 是否匹配
      if (!getPathMatcher().isPattern(path)) {
         urls.add(path);
      }
   }
   return urls;
}Copy to clipboardErrorCopied

handlerMethod 和 name 绑定

String name = null;
if (getNamingStrategy() != null) {
   // 获取名字
   // 类名#方法名
   name = getNamingStrategy().getName(handlerMethod, mapping);
   // 设置 handlerMethod + name 的关系
   addMappingName(name, handlerMethod);
}Copy to clipboardErrorCopied
  • org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrategy#getName
@Override
public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
   if (mapping.getName() != null) {
      return mapping.getName();
   }
   StringBuilder sb = new StringBuilder();
   // 短类名
   String simpleTypeName = handlerMethod.getBeanType().getSimpleName();
   for (int i = 0; i < simpleTypeName.length(); i++) {
      if (Character.isUpperCase(simpleTypeName.charAt(i))) {
         sb.append(simpleTypeName.charAt(i));
      }
   }
   // 组装名称
   // 类名+#+方法名称
   sb.append(SEPARATOR).append(handlerMethod.getMethod().getName());
   return sb.toString();
}Copy to clipboardErrorCopied

initCorsConfiguration

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initCorsConfiguration
@Override
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
   // 创建 handlerMethod
   HandlerMethod handlerMethod = createHandlerMethod(handler, method);
   // 获取 beanType
   Class<?> beanType = handlerMethod.getBeanType();
   // 获取跨域注解 CrossOrigin
   CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class);
   CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
   if (typeAnnotation == null && methodAnnotation == null) {
      return null;
   }
   // 跨域信息配置
   CorsConfiguration config = new CorsConfiguration();
   // 更新跨域配置
   updateCorsConfig(config, typeAnnotation);
   updateCorsConfig(config, methodAnnotation);
   if (CollectionUtils.isEmpty(config.getAllowedMethods())) {
      // 跨域配置赋给方法
      for (RequestMethod allowedMethod : mappingInfo.getMethodsCondition().getMethods()) {
         config.addAllowedMethod(allowedMethod.name());
      }
   }
   // 应用跨域
   return config.applyPermitDefaultValues();
}Copy to clipboardErrorCopied

unregister

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#unregister
    移除 mapping 信息
  • 执行 map , list 相关的移除方法.
public void unregister(T mapping) {
   this.readWriteLock.writeLock().lock();
   try {
      MappingRegistration<T> definition = this.registry.remove(mapping);
      if (definition == null) {
         return;
      }
      this.mappingLookup.remove(definition.getMapping());
      for (String url : definition.getDirectUrls()) {
         List<T> list = this.urlLookup.get(url);
         if (list != null) {
            list.remove(definition.getMapping());
            if (list.isEmpty()) {
               this.urlLookup.remove(url);
            }
         }
      }
      removeMappingName(definition);
      this.corsLookup.remove(definition.getHandlerMethod());
   }
   finally {
      this.readWriteLock.writeLock().unlock();
   }
}
相关文章
|
7月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】
|
2月前
|
JSON 前端开发 Java
Spring MVC详解(上)
本文介绍了MVC架构及其在Spring MVC框架中的应用。MVC将应用程序分为模型、视图和控制器三部分,分别负责数据处理、用户界面展示和请求处理。Spring MVC作为MVC模式的具体实现,不仅是一个web框架,还提供了强大的功能支持,如URL路由映射、参数传递、JSON数据处理、文件上传等。文章详细讲解了如何在Spring MVC中使用`@RequestMapping`、`@RequestParam`、`@RequestBody`、`@PathVariable`等注解来处理HTTP请求,并展示了具体的代码示例和操作步骤。
63 1
|
5月前
|
前端开发 Java 应用服务中间件
我以为我对Spring MVC很了解,直到我遇到了...
所有人都知道Spring MVC是是开发的,却鲜有人知道Spring MVC的理论基础来自于1978 年提出MVC模式的一个老头子,他就是Trygve Mikkjel Heyerdahl Reenskaug,挪威计算机科学家,名誉教授。Trygve Reenskaug的MVC架构思想早期用于图形用户界面(GUI) 的软件设计,他对MVC是这样解释的。MVC 被认为是解决用户控制大型复杂数据集问题的通用解决方案。最困难的部分是为不同的架构组件想出好的名字。模型-视图-编辑器是第一个。
133 1
我以为我对Spring MVC很了解,直到我遇到了...
|
7月前
|
存储 前端开发 Java
Spring MVC
Spring MVC
50 2
|
7月前
|
设计模式 前端开发 Java
初识Spring MVC
初识Spring MVC
38 0
|
存储 前端开发 搜索推荐
(八)Spring源码解析:Spring MVC
(八)Spring源码解析:Spring MVC
98 1
|
监控 安全 前端开发
|
JSON 前端开发 Java
Spring MVC(下)
Spring MVC(下)
|
JSON 前端开发 数据可视化
Spring MVC(上)
Spring MVC(上)
|
设计模式 开发框架 JSON
“一锅端“ Spring MVC 常见使用大全(上)
“一锅端“ Spring MVC 常见使用大全(上)