转载

spring-mvc-handlerMapping 是怎么存放我们的请求路径的-源码

  1. HandlerExecutionChain , 这个是执行链
  2. HandlerMethod 这个就是我们常用的请求的封装(也是本文的目标)
  3. HandlerAdapter 适配器(处理请求的就是从它开始)
  4. HandlerExecutionChain.handler 属性 就是 HandlerMethod
  5. HandlerAdapter 中最后执行的也是 ServletInvocableHandlerMethod 也是从 HandlerMethod 封装的

说明:本文只对 HandlerMethod 的获取进行分析,不对mvc的执行流程分析,所有的一起源码都是针对常见的请求(@Controller 和 @RequestMapping)

HandlerMethod的获取

上面已经知道了最后执行的是HandlerExecutionChain.handler,那就看看这个属性是如何被赋值的

方法入口为DispatcherServlet.doDispatch.getHandler()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
    try {
    ModelAndView mv = null;
    Exception dispatchException = null;
    
    try {
    	processedRequest = checkMultipart(request);
    	multipartRequestParsed = (processedRequest != request);
    
    	// Determine handler for the current request.
    	//就是在这个地方获取的 handlerExecutionChain,也是在这里获取的 handlerMethod
    	mappedHandler = getHandler(processedRequest);
    	if (mappedHandler == null) {
    		noHandlerFound(processedRequest, response);
    		return;
    	}
    
    	// Determine handler adapter for the current request.
    	//获取适配器
    	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    	// Process last-modified header, if supported by the handler.
    	String method = request.getMethod();
    	boolean isGet = "GET".equals(method);
    	if (isGet || "HEAD".equals(method)) {
    		long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    		if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    			return;
    		}
    	}
                          // 拦截器的执行
    	if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    		return;
    	}
    
    	// Actually invoke the handler.
    	//执行请求
    	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                            .....................................
}

上述代码 删除无关代码,继续往下:

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
		       //文章开头说了 handlerMethod 是在 handlerExceutionChain 中,所以在这个代码里
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
             //就是在这里获取的  handlerMethod  也就是请求的映射关系
	Object handler = getHandlerInternal(request);
	if (handler == null) {
		handler = getDefaultHandler();
	}
	if (handler == null) {
		return null;
	}
	// Bean name or resolved handler?
	if (handler instanceof String) {
		String handlerName = (String) handler;
		handler = obtainApplicationContext().getBean(handlerName);
	}
             //获取 执行链 把 handlerMethod 放入 HandlerExecutionChain
	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

	if (logger.isTraceEnabled()) {
		logger.trace("Mapped to " + handler);
	}
	else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
		logger.debug("Mapped to " + executionChain.getHandler());
	}

	if (CorsUtils.isCorsRequest(request)) {
		CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}

	return executionChain;
}
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //根据request 获取 请求路径 里面东西还挺多,不多也就是获取路径的
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	this.mappingRegistry.acquireReadLock();
	try {
	       //获取 handlerMethod
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List matches = new ArrayList<>();
    //这里根据请求路径获取requsetMappingInfo  格式为  [{GET /xml, produces [application/xml]}]
    //请求方式,请求路径,响应类型   注意 现在这个类 是requestMappingHandlerMapping 的一个父类
    // 说明 这也信息有可能是在 requestMappingHandlerMapping 初始化的时候放进去的.
    List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        //获取 Match 的方法 Match 中包含 HandlerMethod
    	addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
    	// No choice but to go through all mappings...
    	addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }
    
    if (!matches.isEmpty()) {
    	Comparator comparator = new MatchComparator(getMappingComparator(request));
    	matches.sort(comparator);
    	Match bestMatch = matches.get(0);
    	if (matches.size() > 1) {
    		if (logger.isTraceEnabled()) {
    			logger.trace(matches.size() + " matching mappings: " + matches);
    		}
    		if (CorsUtils.isPreFlightRequest(request)) {
    			return PREFLIGHT_AMBIGUOUS_MATCH;
    		}
    		Match secondBestMatch = matches.get(1);
    		if (comparator.compare(bestMatch, secondBestMatch) == 0) {
    			Method m1 = bestMatch.handlerMethod.getMethod();
    			Method m2 = secondBestMatch.handlerMethod.getMethod();
    			String uri = request.getRequestURI();
    			throw new IllegalStateException(
    					"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
    		}
    	}
    	request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
    	handleMatch(bestMatch.mapping, lookupPath, request);
    	// 发现返回的 handlerMethod 是 Match 属性  所以我们关注 matches 就行了
    	return bestMatch.handlerMethod;
    }
    else {
    	return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}
private void addMatchingMappings(Collection mappings, List matches, HttpServletRequest request) {
	for (T mapping : mappings) {
	    //这里又去获取了一次  requestMappingInfo  我以为不知道为啥又去获取了一次
		T match = getMatchingMapping(mapping, request);
		if (match != null) {
		    //这里创建了Match  点进去发现传了两个参数  一个是requestMapping 一个是 HandlerMethod
		    //现在主要看下 this.mappingRegistry.getMappings().get(mapping))
			matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
		}
	}
}
public Map getMappings() {
	return this.mappingLookup;
}
//到这里可以看到了  HandlerMethod 是从mappingLookup获取的
private final Map mappingLookup = new LinkedHashMap<>();

下面就要mappingLookup是什么时候被赋值的

mappingLookup 是 MappingRegistry 的属性 MappingRegistry 是 AbstractHandlerMethodMapping的内部类

映射关系是在哪里被加载进去的

思路: 在MappingRegistry.put() 的地方debug,观察执行栈

重要执行节点:requestMappingHandlerMapping初始化-> afterPropertiesSet()

  1. requestMappingHandlerMapping初始化就不看了,是spring-ioc 的东西,以后会讲
  2. requestMappingHandlerMapping的父类AbstractHandlerMethodMapping实现了InitializingBean接口
  3. spring bean 初始化之后 会执行 @PostConstruct 注解的 方法 实现了InitializingBean接口 的afterPropertiesSet()方法,我们这里用到的是InitializingBean

贴代码如下:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

	boolean isInitializingBean = (bean instanceof InitializingBean);
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
		}
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged((PrivilegedExceptionAction) () -> {
					((InitializingBean) bean).afterPropertiesSet();
					return null;
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
		    //这里就是入口
			((InitializingBean) bean).afterPropertiesSet();
		}
	}

	if (mbd != null && bean.getClass() != NullBean.class) {
		String initMethodName = mbd.getInitMethodName();
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}
@Override
public void afterPropertiesSet() {
    //这堆配置 具体是啥我也不知道
	this.config = new RequestMappingInfo.BuilderConfiguration();
	this.config.setUrlPathHelper(getUrlPathHelper());
	this.config.setPathMatcher(getPathMatcher());
	this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
	this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
	this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
	this.config.setContentNegotiationManager(getContentNegotiationManager());
          //看这里,调用了父类的 afterPropertiesSet();
	super.afterPropertiesSet();();
}
@Override
public void afterPropertiesSet() {
        //这里
	initHandlerMethods();
}

//这里
protected void initHandlerMethods() {
        //getCandidateBeanNames()  应该是获取了所有的beanName
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
		    //就是这里
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}
//根绝beanName处理的
protected void processCandidateBean(String beanName) {
	Class beanType = null;
	try {
	       //获取当前bean的class 类型
		beanType = obtainApplicationContext().getType(beanName);
	}
	catch (Throwable ex) {
		// An unresolvable bean type, probably from a lazy bean - let's ignore it.
		if (logger.isTraceEnabled()) {
			logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
		}
	}
	//这里 重点 isHandler() 判断是否需要处理
	if (beanType != null && isHandler(beanType)) {
	        //假如是的话,继续 (重点)
		detectHandlerMethods(beanName);
	}
}

// 看到了,条件就是 当前类是否存在 @Controller  @RequestMapping 注解
protected boolean isHandler(Class beanType) {
	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

下面的代码就是最后了,注意看! 下面的代码比较绕,用的是java8的Lambda 表达式,假如对java8比较熟,看这段代码是无压力的 先把这几个方法的代码都贴出来,如下:

protected void detectHandlerMethods(Object handler) {
	Class handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
	    //获取当前contorller 类型
		Class userType = ClassUtils.getUserClass(handlerType);
		// 第一步  就是这里   执行selectMethods   这个方法 传递了一个行为(lambda表达式)
		Map methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup) method -> {
					try {
					    //第六步
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		//第七步  
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

public static  Map selectMethods(Class targetType, final MetadataLookup metadataLookup) {
	final Map methodMap = new LinkedHashMap<>();
	Set> handlerTypes = new LinkedHashSet<>();
	Class specificHandlerType = null;
    //判断是否存在代理
	if (!Proxy.isProxyClass(targetType)) {
		specificHandlerType = ClassUtils.getUserClass(targetType);
		handlerTypes.add(specificHandlerType);
	}
	handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
    //循环 第二步 目标 controller  正常情况就一个元素
	for (Class currentHandlerType : handlerTypes) {
		final Class targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
        // 调用 doWithMethods  第三步
		ReflectionUtils.doWithMethods(currentHandlerType, method -> {
		    //第五步  获取到了 method
			Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
			T result = metadataLookup.inspect(specificMethod);
			if (result != null) {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
				if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
					methodMap.put(specificMethod, result);
				}
			}
		}, ReflectionUtils.USER_DECLARED_METHODS);
	}

	return methodMap;
}
public static void doWithMethods(Class clazz, MethodCallback mc, @Nullable MethodFilter mf) {
	// Keep backing up the inheritance hierarchy.
	//获取所有的方法
	Method[] methods = getDeclaredMethods(clazz);
	for (Method method : methods) {
		if (mf != null && !mf.matches(method)) {
			continue;
		}
		try {
		    //执行 selectMethods 方法中的 MethodFilter mf  第四步
			mc.doWith(method);
		}
		catch (IllegalAccessException ex) {
			throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
		}
	}
	if (clazz.getSuperclass() != null) {
		doWithMethods(clazz.getSuperclass(), mc, mf);
	}
	else if (clazz.isInterface()) {
		for (Class superIfc : clazz.getInterfaces()) {
			doWithMethods(superIfc, mc, mf);
		}
	}
}

//保存对应关系入口
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	this.mappingRegistry.register(mapping, handler, method);
}

//结束了
public void register(T mapping, Object handler, Method method) {
	this.readWriteLock.writeLock().lock();
	try {
		HandlerMethod handlerMethod = createHandlerMethod(handler, method);
		assertUniqueMethodMapping(handlerMethod, mapping);
		//保存到  mappingLookup
		this.mappingLookup.put(mapping, handlerMethod);

		List directUrls = getDirectUrls(mapping);
		for (String url : directUrls) {
		    //保存路径到urlLookup
			this.urlLookup.add(url, mapping);
		}
		// 

		String name = null;
		if (getNamingStrategy() != null) {
			name = getNamingStrategy().getName(handlerMethod, mapping);
			addMappingName(name, handlerMethod);
		}

		CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
		if (corsConfig != null) {
			this.corsLookup.put(handlerMethod, corsConfig);
		}

		this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
	}
	finally {
		this.readWriteLock.writeLock().unlock();
	}
}

总结:

  1. spring-ioc 初始化 requestMappingHandlerMapping 的时候 把对应关系 存放在mappingLookup
  2. 执行的时候 根绝请求路径 查找urlLookup,再根据 urlLookup 的val 当做key 去 mappingLookup 中查找
原文  https://juejin.im/post/5ddf84f1f265da05b2511c77
正文到此结束
Loading...