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

[系统运维] 时间:2025-11-05 02:42:24 来源:益强IT技术网 作者:数据库 点击:116次

概述

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

SpringMVC处理的流程:

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

一个请求的心组处理过程

获取HandlerMapping

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

public class DispatcherServlet extends FrameworkServlet {   private List<HandlerMapping> handlerMappings;   private void initHandlerMappings(ApplicationContext context) {     // 在ApplicationContext中查找所有HandlerMappings,心组包括祖先上下文。心组     Map<String,心组 HandlerMapping> 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<HandlerMapping> 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接口,是IT技术网心组由顺序的,那在这里,心组谁先匹配谁就处理       for (HandlerMapping mapping : this.handlerMappings) {        // 在这个过程中会通过查找到的心组HandlerMapping对象,然后获取合适的心组处理程序(可能是个Bean对象或是HandlerMethod对象等)         HandlerExecutionChain handler = mapping.getHandler(request);         if (handler != null) {           return handler;         }       }     }     return null;   } } 

系统默认有如下5个HandlerMapping

RequestMappingHandlerMapping BeanNameUrlHandlerMapping RouterFunctionMapping SimpleUrlHandlerMapping 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<Match> matches = new ArrayList<>();     // 在已注册的Mapping中根据请求的url进行查找     // 这样查找的香港云服务器this.pathLookup.get(urlPath);     List<T> 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<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) 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);       }     }   } } 

(责任编辑:应用开发)

    相关内容
    精彩推荐
    热门点击
    友情链接