springmvc源码笔记-RequestMappingHandlerMapping

  1. 下图是springmvc的执行流程

    5220087-3c0f59d3c39a12dd

    图片来源:https://www.jianshu.com/p/8a20c547e245


     DispatcherServlet根据url定位到Controller和方法,依赖的是HandlerMapping接口的各个实现类,其中,RequestMappingHandlerMapping是专门用来处理注解方式的Controller的
    

    下面,我们分RequestMappingHandlerMapping的加载以及RequestMappingHandlerMapping如何根据url定位Controller两部分来讲

    RequestMappingHandlerMapping加载过程

    1. RMHP在系统启动时会被注册成bean,见《springmvc源码笔记-HandlerMapping注入》

    2. 因为RMHP实现了InitializingBean接口,在bean加载完成后会自动调用afterPropertiesSet方法,在此方法中调用了AbstractHandlerMethodMapping#initHandlerMethods()来实现初始化

      protected void initHandlerMethods() {
      	// 遍历所有的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 {
      		beanType = obtainApplicationContext().getType(beanName);
      	}
      	......
      	// isHandler判断类是否有Controller或者RequestMapping注解
      	if (beanType != null && isHandler(beanType)) {
      		detectHandlerMethods(beanName);
      	}
      }
      
      protected void detectHandlerMethods(Object handler) {
      	......
      	if (handlerType != null) {
      		Class<?> userType = ClassUtils.getUserClass(handlerType);
      		// 遍历类的所有方法
      		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
      				(MethodIntrospector.MetadataLookup<T>) method -> {
      					try {
      						// 获取方法上的映射(会读取方法上的RequestMapping注解获取url)
      						return getMappingForMethod(method, userType);
      					}
      					catch (Throwable ex) {
      						throw new IllegalStateException("Invalid mapping on handler class [" +
      								userType.getName() + "]: " + method, ex);
      					}
      				});
      		......
      		methods.forEach((method, mapping) -> {
      			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
      			// 将映射关系放入AbstractHandlerMethodMapping.mappingRegistry中
      			registerHandlerMethod(handler, invocableMethod, mapping);
      		});
      	}
      }
      

    RequestMappingHandlerMapping解析过程

    1. DispatcherServlet继承HttpServlet,所以执行链是FrameworkServlet#doGet→DispatcherServlet#doService→DispatcherServlet#doDispatch→DispatcherServlet#getHandler

      protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      	if (this.handlerMappings != null) {
      		// handlerMappings已在onRefresh方法中初始化
      		for (HandlerMapping mapping : this.handlerMappings) {
      			// 第一个mapping就是RequestMappingHandlerMapping
      			// 获取处理程序,也就是url对应的controller和method
      			HandlerExecutionChain handler = mapping.getHandler(request);
      			if (handler != null) {
      				return handler;
      			}
      		}
      	}
      	return null;
      }
      
      // AbstractHandlerMapping#getHandler->RequestMappingHandlerMapping#getHandlerInternal->AbstractHandlerMapping#lookupHandlerMethod
      protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
      	// lookupPath就是请求路径
      	List<Match> matches = new ArrayList<>();
      	// 获取url路径匹配项
      	List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
      	if (directPathMatches != null) {
      		// 添加映射匹配集合
      		addMatchingMappings(directPathMatches, matches, request);
      	}
      	if (matches.isEmpty()) {
      		addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
      	}
      	if (!matches.isEmpty()) {
      		......
      		// 至此,根据url获取到controller和method
      		return bestMatch.getHandlerMethod();
      	} else {
      		return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
      	}
      }
      
      private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
      	for (T mapping : mappings) {
      		T match = getMatchingMapping(mapping, request);
      		if (match != null) {
      			// this.mappingRegistry.getRegistrations().get(mapping)就是获取HandlerMethodMapping
      			// HandlerMethodMapping保存controller和method信息的类
      			matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
      		}
      	}
      }
      
posted @ 2021-04-23 14:24  王谷雨  阅读(181)  评论(0编辑  收藏  举报