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

开发 前端
当一个请求过来后Spring是如何进行处理的?下面简单的罗列下请个的过程中核心组件,希望能够帮助到你。

[[437989]]

概述

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

SpringMVC处理的流程:

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

一个请求的处理过程

获取HandlerMapping

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

  1. public class DispatcherServlet extends FrameworkServlet { 
  2.   private List<HandlerMapping> handlerMappings; 
  3.   private void initHandlerMappings(ApplicationContext context) { 
  4.     // 在ApplicationContext中查找所有HandlerMappings,包括祖先上下文。 
  5.     Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, truefalse); 
  6.     if (!matchingBeans.isEmpty()) { 
  7.       this.handlerMappings = new ArrayList<>(matchingBeans.values()); 
  8.       AnnotationAwareOrderComparator.sort(this.handlerMappings); 
  9.     } 
  10.   } 

查找HandlerMapping

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

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

系统默认有如下5个HandlerMapping

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

一般默认都是RequestMappingHandlerMapping匹配

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

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

  1. public abstract class AbstractHandlerMapping { 
  2.   public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 
  3.     Object handler = getHandlerInternal(request); 
  4.     // ... 
  5.     HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); 
  6.     // ... 
  7.     return executionChain; 
  8.     } 
  9.    
  10. public abstract class AbstractHandlerMethodMapping { 
  11.   protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { 
  12.     // 获取请求地址 
  13.     String lookupPath = initLookupPath(request); 
  14.     try { 
  15.       // 根据请求地址查询对应的HandlerMethod 
  16.       HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); 
  17.       return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); 
  18.     } 
  19.     // ... 
  20.   } 
  21.   protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { 
  22.     List<Match> matches = new ArrayList<>(); 
  23.     // 在已注册的Mapping中根据请求的url进行查找 
  24.     // 这样查找的this.pathLookup.get(urlPath); 
  25.     List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath); 
  26.     if (!matches.isEmpty()) { 
  27.       Match bestMatch = matches.get(0); 
  28.       // ... 
  29.       handleMatch(bestMatch.mapping, lookupPath, request); 
  30.       return bestMatch.getHandlerMethod(); 
  31.     } 
  32.     // ... 
  33.   } 

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

初始化HandlerMethod

  1. public class RequestMappingHandlerMapping { 
  2.   public void afterPropertiesSet() { 
  3.     // ... 
  4.     super.afterPropertiesSet(); 
  5.   } 
  6. public abstract class AbstractHandlerMethodMapping { 
  7.   public void afterPropertiesSet() { 
  8.     initHandlerMethods(); 
  9.   } 
  10.   protected void initHandlerMethods() { 
  11.     // getCandidateBeanNames获取容器中的所有Bean 
  12.         for (String beanName : getCandidateBeanNames()) { 
  13.       if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { 
  14.         processCandidateBean(beanName); 
  15.       } 
  16.     } 
  17.     handlerMethodsInitialized(getHandlerMethods()); 
  18.   } 
  19.   protected void processCandidateBean(String beanName) { 
  20.     Class<?> beanType = null
  21.     try { 
  22.       // 根据BeanName获取对应的Class 
  23.       beanType = obtainApplicationContext().getType(beanName); 
  24.     } 
  25.     // ... 
  26.     // isHandler方法判断当前的类是否符合条件,该方法在RequestMappingHandlerMapping中实现 
  27.     // isHandler方法用处就是判断当前的Class@Controller或者@RequestMapping注解 
  28.     // 这样就将所有的@Controller与RequestMappingHandlerMapping关联一起了。 
  29.     if (beanType != null && isHandler(beanType)) { 
  30.       // 查找所有的HandlerMethod 
  31.       detectHandlerMethods(beanName); 
  32.     } 
  33.   } 
  34.   protected void detectHandlerMethods(Object handler) { 
  35.     Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); 
  36.     if (handlerType != null) { 
  37.       Class<?> userType = ClassUtils.getUserClass(handlerType); 
  38.       // 查找Class中的所有方法 
  39.       Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { 
  40.         try { 
  41.           // 将每一个符合条件的方法(方法上有@RequestMapping注解的) 
  42.           // 封装到RequestMappingInfo对象中 
  43.           return getMappingForMethod(method, userType); 
  44.         } 
  45.         // ... 
  46.       }); 
  47.       methods.forEach((method, mapping) -> { 
  48.         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); 
  49.         // 将找到的所有Method进行注册添加到Map中 
  50.         registerHandlerMethod(handler, invocableMethod, mapping); 
  51.       }); 
  52.     } 
  53.   } 
  54.   protected void registerHandlerMethod(Object handler, Method method, T mapping) { 
  55.     this.mappingRegistry.register(mapping, handler, method); 
  56.   } 
  57.   class MappingRegistry { 
  58.     // T  : RequestMappingInfo, handler: 字符串(usersController)Bean名称,method:请求方法对象 
  59.     public void register(T mapping, Object handler, Method method) { 
  60.       // 创建HandlerMethod对象 
  61.       HandlerMethod handlerMethod = createHandlerMethod(handler, method); 
  62.       // ... 
  63.       for (String path : directPaths) { 
  64.         // 缓存上,在请求到来的时候 会从这个pathLookup集合中查找 
  65.         this.pathLookup.add(path, mapping); 
  66.       } 
  67.     } 
  68.   } 

 

责任编辑:姜华 来源: 今日头条
相关推荐

2021-03-26 11:00:50

SpringMVC组件接口

2022-12-07 08:56:27

SpringMVC核心组件

2024-03-27 13:33:00

MySQLInnoDB事务

2022-07-11 08:48:52

业务转型CIO

2024-04-01 08:29:09

Git核心实例

2022-10-24 00:33:59

MySQL全局锁行级锁

2023-06-07 14:07:00

架构

2009-07-17 12:54:13

2018-10-25 09:26:07

VLANVXLAN网络

2022-01-05 07:07:37

Go核心设计

2012-01-13 13:05:41

Scale Out网络

2021-10-12 10:50:31

鸿蒙HarmonyOS应用

2011-04-22 10:13:35

SimpleFrame

2021-02-19 08:38:36

Kubernetes容器化分布式

2023-02-09 08:01:12

核心组件非阻塞

2022-09-30 10:44:47

Netty组件数据

2023-11-10 10:51:15

Python

2010-09-01 09:48:32

DHCP报文格式

2010-08-04 15:01:00

2009-06-22 14:36:09

ITIL运维管理摩卡软件
点赞
收藏

51CTO技术栈公众号