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();
   }
}
相关文章
|
4月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】
|
2月前
|
前端开发 安全 Java
什么是Spring MVC?它解决了什么问题?
Spring框架就像一个家族,有众多衍生产品例如boot、security、jpa等等。但他们的基础都是Spring的ioc和aop。ioc提供了依赖注入的容器,aop解决了面向横切面的编程;然后在此二者的基础上实现了其他延伸产品的高级功能。
20 0
|
8月前
|
监控 安全 前端开发
|
8月前
|
JSON 前端开发 Java
Spring MVC(下)
Spring MVC(下)
|
8月前
|
JSON 前端开发 搜索推荐
“一锅端“ Spring MVC 常见使用大全(下)
“一锅端“ Spring MVC 常见使用大全(下)
|
9月前
|
存储 前端开发 搜索推荐
(八)Spring源码解析:Spring MVC
(八)Spring源码解析:Spring MVC
54 1
|
5月前
|
设计模式 前端开发 Java
spring MVC
spring MVC
24 0
|
8月前
|
JSON 前端开发 Java
Spring MVC详解
Spring MVC详解
|
11月前
|
XML JSON 前端开发
Spring MVC-03循序渐进之Spring MVC
Spring MVC-03循序渐进之Spring MVC
50 0
|
前端开发 Java 应用服务中间件
5 分钟彻底理解 Spring MVC(下)
处理器配置 看到这里,细心的小伙伴可能会有疑问,说好的 DispatcherServlet 将请求分派给 Controller 呢?这里暂时不用着急,Controller 其实是 Spring MVC 的处理器类型之一,这里的 HttpRequestHandler 同样是 Spring MVC 的处理器。
83 0
5 分钟彻底理解 Spring MVC(下)