MappingRegistry

  • Author: HuiFer
  • 源码阅读仓库: SourceHot-spring
  • 源码路径: org.springframework.jms.annotation.EnableJms

  • 类全路径

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry
  • 基本属性

    1. class MappingRegistry {
    2. /**
    3. * key:mapping
    4. * value: mapping registration
    5. */
    6. private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
    7. /**
    8. * key: mapping
    9. * value: handlerMethod
    10. */
    11. private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
    12. /**
    13. * key: url
    14. * value: list mapping
    15. */
    16. private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
    17. /**
    18. * key: name
    19. * value: handler method
    20. */
    21. private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
    22. /**
    23. * key:handler method
    24. * value: 跨域配置
    25. */
    26. private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
    27. /**
    28. * 读写锁
    29. */
    30. private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    31. }
  • 写一个简单的 controller 来进行解析

  1. @RestController
  2. @RequestMapping("/demo")
  3. public class DemoController {
  4. @GetMapping("/do")
  5. public Object go() {
  6. return "fff";
  7. }
  8. }
  • 前置链路追踪

    • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#registerHandlerMethod
    1. protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
    2. super.registerHandlerMethod(handler, method, mapping);
    3. this.updateConsumesCondition(mapping, method);
    4. }
    • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod
    1. protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    2. this.mappingRegistry.register(mapping, handler, method);
    3. }
    • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register

      本文重点的方法

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

image-20200918130340555

createHandlerMethod

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod
  1. protected HandlerMethod createHandlerMethod(Object handler, Method method) {
  2. // 是否是字符串
  3. if (handler instanceof String) {
  4. // 创建对象
  5. return new HandlerMethod((String) handler,
  6. obtainApplicationContext().getAutowireCapableBeanFactory(), method);
  7. }
  8. return new HandlerMethod(handler, method);
  9. }
  • HandlerMethod 构造函数

    1. public HandlerMethod(String beanName, BeanFactory beanFactory, Method method){}
    2. public HandlerMethod(Object bean, Method method) {}

HandlerMethod

  • 成员变量
  1. public class HandlerMethod {
  2. /** Logger that is available to subclasses. */
  3. protected final Log logger = LogFactory.getLog(getClass());
  4. /**
  5. * beanName 或者 bean 实例
  6. */
  7. private final Object bean;
  8. /**
  9. * 上下文
  10. */
  11. @Nullable
  12. private final BeanFactory beanFactory;
  13. /**
  14. * bean 类型
  15. */
  16. private final Class<?> beanType;
  17. /**
  18. * 处理方法
  19. */
  20. private final Method method;
  21. private final Method bridgedMethod;
  22. /**
  23. * 方法参数
  24. */
  25. private final MethodParameter[] parameters;
  26. }

validateMethodMapping

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

HandlerMethod 进行验证

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

getDirectUrls

  • 找到 mapping 匹配的 url

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

  1. private List<String> getDirectUrls(T mapping) {
  2. List<String> urls = new ArrayList<>(1);
  3. // mapping.getPatternsCondition().getPatterns()
  4. for (String path : getMappingPathPatterns(mapping)) {
  5. // 是否匹配
  6. if (!getPathMatcher().isPattern(path)) {
  7. urls.add(path);
  8. }
  9. }
  10. return urls;
  11. }

handlerMethod 和 name 绑定

  1. String name = null;
  2. if (getNamingStrategy() != null) {
  3. // 获取名字
  4. // 类名#方法名
  5. name = getNamingStrategy().getName(handlerMethod, mapping);
  6. // 设置 handlerMethod + name 的关系
  7. addMappingName(name, handlerMethod);
  8. }
  • org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMethodMappingNamingStrategy#getName
  1. @Override
  2. public String getName(HandlerMethod handlerMethod, RequestMappingInfo mapping) {
  3. if (mapping.getName() != null) {
  4. return mapping.getName();
  5. }
  6. StringBuilder sb = new StringBuilder();
  7. // 短类名
  8. String simpleTypeName = handlerMethod.getBeanType().getSimpleName();
  9. for (int i = 0; i < simpleTypeName.length(); i++) {
  10. if (Character.isUpperCase(simpleTypeName.charAt(i))) {
  11. sb.append(simpleTypeName.charAt(i));
  12. }
  13. }
  14. // 组装名称
  15. // 类名+#+方法名称
  16. sb.append(SEPARATOR).append(handlerMethod.getMethod().getName());
  17. return sb.toString();
  18. }

initCorsConfiguration

  • org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initCorsConfiguration
  1. @Override
  2. protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
  3. // 创建 handlerMethod
  4. HandlerMethod handlerMethod = createHandlerMethod(handler, method);
  5. // 获取 beanType
  6. Class<?> beanType = handlerMethod.getBeanType();
  7. // 获取跨域注解 CrossOrigin
  8. CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(beanType, CrossOrigin.class);
  9. CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
  10. if (typeAnnotation == null && methodAnnotation == null) {
  11. return null;
  12. }
  13. // 跨域信息配置
  14. CorsConfiguration config = new CorsConfiguration();
  15. // 更新跨域配置
  16. updateCorsConfig(config, typeAnnotation);
  17. updateCorsConfig(config, methodAnnotation);
  18. if (CollectionUtils.isEmpty(config.getAllowedMethods())) {
  19. // 跨域配置赋给方法
  20. for (RequestMethod allowedMethod : mappingInfo.getMethodsCondition().getMethods()) {
  21. config.addAllowedMethod(allowedMethod.name());
  22. }
  23. }
  24. // 应用跨域
  25. return config.applyPermitDefaultValues();
  26. }

unregister

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

    移除 mapping 信息

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

  1. public void unregister(T mapping) {
  2. this.readWriteLock.writeLock().lock();
  3. try {
  4. MappingRegistration<T> definition = this.registry.remove(mapping);
  5. if (definition == null) {
  6. return;
  7. }
  8. this.mappingLookup.remove(definition.getMapping());
  9. for (String url : definition.getDirectUrls()) {
  10. List<T> list = this.urlLookup.get(url);
  11. if (list != null) {
  12. list.remove(definition.getMapping());
  13. if (list.isEmpty()) {
  14. this.urlLookup.remove(url);
  15. }
  16. }
  17. }
  18. removeMappingName(definition);
  19. this.corsLookup.remove(definition.getHandlerMethod());
  20. }
  21. finally {
  22. this.readWriteLock.writeLock().unlock();
  23. }
  24. }