SpringMVC核心组件HandlerMapping你清楚了吗?

环境:Springboot2.4.11


概述

当一个请求过来后Spring是如何进行处理的?下面简单的罗列下请个的过程中核心组件

SpringMVC处理的流程:

  1. DispatcherServlet 所有请求的入口
  2. HandlerMapping 将请求地址与处理程序关联
  3. HandlerAdapter 真正的处理程序,如执行上一步中对应的处理程序
  4. HandlerMethodArgumentResolver 对参数进行解析,这里面还涉及到很多其它东西
  5. HanlderMethodReturnValueHandler 对返回值进行输出处理
  6. ViewResolver 当上一步返回结果为ModelAndView时会应用视图解析器

一个请求的处理过程

获取HandlerMapping

该步从容器中获取所有的HandlerMapping对象。

public class DispatcherServlet extends FrameworkServlet {
  private List handlerMappings;
  private void initHandlerMappings(ApplicationContext context) {
    // 在ApplicationContext中查找所有HandlerMappings,包括祖先上下文。
    Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    if (!matchingBeans.isEmpty()) {
      this.handlerMappings = new ArrayList<>(matchingBeans.values());
      AnnotationAwareOrderComparator.sort(this.handlerMappings);
    }
  }
}

查找HandlerMapping

该步从获取的HandlerMapping中查找适合当前请求的HandlerMapping。

public class DispatcherServlet extends FrameworkServlet {
  private List handlerMappings;
  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerExecutionChain mappedHandler = null;
    // 查找能够处理当前请求HandlerMapping对象,主要就是根据请求的URI
    mappedHandler = getHandler(processedRequest);
  }
  protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
      // HandlerMapping 实现了Ordered接口,是由顺序的,那在这里,谁先匹配谁就处理
      for (HandlerMapping mapping : this.handlerMappings) {
       // 在这个过程中会通过查找到的HandlerMapping对象,然后获取合适的处理程序(可能是个Bean对象或是HandlerMethod对象等)
        HandlerExecutionChain handler = mapping.getHandler(request);
        if (handler != null) {
          return handler;
        }
      }
    }
    return null;
  }
}

系统默认有如下5个HandlerMapping

  1. RequestMappingHandlerMapping
  2. BeanNameUrlHandlerMapping
  3. RouterFunctionMapping
  4. SimpleUrlHandlerMapping
  5. WelcomePageHandlerMapping

一般默认都是RequestMappingHandlerMapping匹配

接下来看看是如何进行匹配的

调用父类AbstractHandlerMapping#getHandler方法,父类中的这个方法中定义了特定的逻辑,而针对每种不同的HandlerMapping实现是需要具体的子类来实现AbstractHandlerMapping#getHandlerInternal方法

public abstract class AbstractHandlerMapping {
  public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Object handler = getHandlerInternal(request);
    // ...
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    // ...
    return executionChain;
	}
  
}
public abstract class AbstractHandlerMethodMapping {
  protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 获取请求地址
    String lookupPath = initLookupPath(request);
    try {
      // 根据请求地址查询对应的HandlerMethod
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    // ...
  }
  protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List matches = new ArrayList<>();
    // 在已注册的Mapping中根据请求的url进行查找
    // 这样查找的this.pathLookup.get(urlPath);
    List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
    if (!matches.isEmpty()) {
      Match bestMatch = matches.get(0);
      // ...
      handleMatch(bestMatch.mapping, lookupPath, request);
      return bestMatch.getHandlerMethod();
    }
    // ...
  }
}

到这里就是查找处理请求的HandlerMethod对象。接下来看看系统是如何进行初始化所有的HandlerMethod

初始化HandlerMethod

public class RequestMappingHandlerMapping {
  public void afterPropertiesSet() {
    // ...
    super.afterPropertiesSet();
  }
}
public abstract class AbstractHandlerMethodMapping {
  public void afterPropertiesSet() {
    initHandlerMethods();
  }
  protected void initHandlerMethods() {
    // getCandidateBeanNames获取容器中的所有Bean
		for (String beanName : getCandidateBeanNames()) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
        processCandidateBean(beanName);
      }
    }
    handlerMethodsInitialized(getHandlerMethods());
  }
  protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
      // 根据BeanName获取对应的Class
      beanType = obtainApplicationContext().getType(beanName);
    }
    // ...
    // isHandler方法判断当前的类是否符合条件,该方法在RequestMappingHandlerMapping中实现
    // isHandler方法用处就是判断当前的Class@Controller或者@RequestMapping注解
    // 这样就将所有的@Controller与RequestMappingHandlerMapping关联一起了。
    if (beanType != null && isHandler(beanType)) {
      // 查找所有的HandlerMethod
      detectHandlerMethods(beanName);
    }
  }
  protected void detectHandlerMethods(Object handler) {
    Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
    if (handlerType != null) {
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      // 查找Class中的所有方法
      Map methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup) method -> {
        try {
          // 将每一个符合条件的方法(方法上有@RequestMapping注解的)
          // 封装到RequestMappingInfo对象中
          return getMappingForMethod(method, userType);
        }
        // ...
      });
      methods.forEach((method, mapping) -> {
        Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
        // 将找到的所有Method进行注册添加到Map中
        registerHandlerMethod(handler, invocableMethod, mapping);
      });
    }
  }
  protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
  }
  class MappingRegistry {
    // T  : RequestMappingInfo, handler: 字符串(usersController)Bean名称,method:请求方法对象
    public void register(T mapping, Object handler, Method method) {
      // 创建HandlerMethod对象
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      // ...
      for (String path : directPaths) {
        // 缓存上,在请求到来的时候 会从这个pathLookup集合中查找
        this.pathLookup.add(path, mapping);
      }
    }
  }
}

完毕!!!

求个关注+转发

公众:Springboot实战案例锦集

spring data jpa 高级应用

Spring MVC 异常处理方式

Spring事务实现原理源码分析

Spring 自定义Advisor以编程的方式实现AOP

SpringBoot项目中应用Spring Batch批处理框架,处理大数据新方案

Spring IOC容器对Bean实例化的过程详解源码分析

Spring Boot Security防重登录及在线总数

Spring Security记住我功能实现及源码分析

Spring Security 自定义登录成功后的逻辑

SpringMVC核心组件HandlerMapping你清楚了吗?

SpringMVC核心组件HandlerMapping你清楚了吗?

SpringMVC核心组件HandlerMapping你清楚了吗?

SpringMVC核心组件HandlerMapping你清楚了吗?

展开阅读全文

页面更新:2024-04-04

标签:在线   注解   初始化   容器   组件   源码   对象   核心   过程   地址   程序   方法

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top