Skip to content

Latest commit

 

History

History
305 lines (242 loc) · 8.12 KB

Spring-mvc-MappingRegistry.md

File metadata and controls

305 lines (242 loc) · 8.12 KB

MappingRegistry

  • Author: HuiFer

  • 源码阅读仓库: SourceHot-spring

  • 源码路径: org.springframework.jms.annotation.EnableJms

  • 类全路径

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

  • 基本属性

    classMappingRegistry { /** * key:mapping * value: mapping registration */privatefinalMap<T, MappingRegistration<T>> registry = newHashMap<>(); /** * key: mapping * value: handlerMethod */privatefinalMap<T, HandlerMethod> mappingLookup = newLinkedHashMap<>(); /** * key: url * value: list mapping */privatefinalMultiValueMap<String, T> urlLookup = newLinkedMultiValueMap<>(); /** * key: name * value: handler method */privatefinalMap<String, List<HandlerMethod>> nameLookup = newConcurrentHashMap<>(); /** * key:handler method * value: 跨域配置 */privatefinalMap<HandlerMethod, CorsConfiguration> corsLookup = newConcurrentHashMap<>(); /** * 读写锁 */privatefinalReentrantReadWriteLockreadWriteLock = newReentrantReadWriteLock(); }
  • 写一个简单的 controller 来进行解析

@RestController@RequestMapping("/demo") publicclassDemoController { @GetMapping("/do") publicObjectgo() { return"fff"; } }
  • 前置链路追踪

    • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#registerHandlerMethod
    protectedvoidregisterHandlerMethod(Objecthandler, Methodmethod, RequestMappingInfomapping) { super.registerHandlerMethod(handler, method, mapping); this.updateConsumesCondition(mapping, method); }
    • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod
    protectedvoidregisterHandlerMethod(Objecthandler, Methodmethod, Tmapping) { this.mappingRegistry.register(mapping, handler, method); }
    • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register

      本文重点的方法

先将对象截图出来方便后续理解

image-20200918130340555

createHandlerMethod

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod
protectedHandlerMethodcreateHandlerMethod(Objecthandler, Methodmethod) { // 是否是字符串if (handlerinstanceofString) { // 创建对象returnnewHandlerMethod((String) handler, obtainApplicationContext().getAutowireCapableBeanFactory(), method); } returnnewHandlerMethod(handler, method); }
  • HandlerMethod 构造函数

    publicHandlerMethod(StringbeanName, BeanFactorybeanFactory, Methodmethod){} publicHandlerMethod(Objectbean, Methodmethod) {}

HandlerMethod

  • 成员变量
publicclassHandlerMethod { /** Logger that is available to subclasses. */protectedfinalLoglogger = LogFactory.getLog(getClass()); /** * beanName 或者 bean 实例 */privatefinalObjectbean; /** * 上下文 */@NullableprivatefinalBeanFactorybeanFactory; /** * bean 类型 */privatefinalClass<?> beanType; /** * 处理方法 */privatefinalMethodmethod; privatefinalMethodbridgedMethod; /** * 方法参数 */privatefinalMethodParameter[] parameters; }

validateMethodMapping

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

HandlerMethod 进行验证

privatevoidvalidateMethodMapping(HandlerMethodhandlerMethod, Tmapping) { // Assert that the supplied mapping is unique.// 从缓存中获取HandlerMethodexistingHandlerMethod = this.mappingLookup.get(mapping); // 是否为空 , 是否相同if (existingHandlerMethod != null && !existingHandlerMethod.equals(handlerMethod)) { thrownewIllegalStateException( "Ambiguous mapping. Cannot map '" + handlerMethod.getBean() + "' method \n" + handlerMethod + "\nto " + mapping + ": There is already '" + existingHandlerMethod.getBean() + "' bean method\n" + existingHandlerMethod + " mapped."); } }

getDirectUrls

  • 找到 mapping 匹配的 url

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

privateList<String> getDirectUrls(Tmapping) { List<String> urls = newArrayList<>(1); // mapping.getPatternsCondition().getPatterns()for (Stringpath : getMappingPathPatterns(mapping)) { // 是否匹配if (!getPathMatcher().isPattern(path)) { urls.add(path); } } returnurls; }

handlerMethod 和 name 绑定

Stringname = null; if (getNamingStrategy() != null) { // 获取名字// 类名#方法名name = getNamingStrategy().getName(handlerMethod, mapping); // 设置 handlerMethod + name 的关系addMappingName(name, handlerMethod); }
  • org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrategy#getName
@OverridepublicStringgetName(HandlerMethodhandlerMethod, RequestMappingInfomapping) { if (mapping.getName() != null) { returnmapping.getName(); } StringBuildersb = newStringBuilder(); // 短类名StringsimpleTypeName = handlerMethod.getBeanType().getSimpleName(); for (inti = 0; i < simpleTypeName.length(); i++) { if (Character.isUpperCase(simpleTypeName.charAt(i))) { sb.append(simpleTypeName.charAt(i)); } } // 组装名称// 类名+#+方法名称sb.append(SEPARATOR).append(handlerMethod.getMethod().getName()); returnsb.toString(); }

initCorsConfiguration

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initCorsConfiguration
@OverrideprotectedCorsConfigurationinitCorsConfiguration(Objecthandler, Methodmethod, RequestMappingInfomappingInfo) { // 创建 handlerMethodHandlerMethodhandlerMethod = createHandlerMethod(handler, method); // 获取 beanTypeClass<?> beanType = handlerMethod.getBeanType(); // 获取跨域注解 CrossOriginCrossOrigintypeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class); CrossOriginmethodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class); if (typeAnnotation == null && methodAnnotation == null) { returnnull; } // 跨域信息配置CorsConfigurationconfig = newCorsConfiguration(); // 更新跨域配置updateCorsConfig(config, typeAnnotation); updateCorsConfig(config, methodAnnotation); if (CollectionUtils.isEmpty(config.getAllowedMethods())) { // 跨域配置赋给方法for (RequestMethodallowedMethod : mappingInfo.getMethodsCondition().getMethods()) { config.addAllowedMethod(allowedMethod.name()); } } // 应用跨域returnconfig.applyPermitDefaultValues(); }

unregister

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

    移除 mapping 信息

  • 执行 map , list 相关的移除方法.

publicvoidunregister(Tmapping) { this.readWriteLock.writeLock().lock(); try { MappingRegistration<T> definition = this.registry.remove(mapping); if (definition == null) { return; } this.mappingLookup.remove(definition.getMapping()); for (Stringurl : 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(); } }
close