Springmvc中@RequestMapping的实现原理

1、@RequestMapping处理方法的注册与匹配

(1)重要的类、接口
RequestMappingHandlerMapping 入口类
RequestCondition 匹配条件接口,通过其实现类来判断是否匹配处理方法
RequestMappingInfo 匹配条件信息类,实现RequestCondition,并包含多个RequestCondition实现类

(2)RequestMappingHandlerMapping源码解析
以下是注册处理方法的相关源码

// 实现了InitializingBean接口
public void afterPropertiesSet() {
	initHandlerMethods();
}

protected void initHandlerMethods() {
	if (logger.isDebugEnabled()) {
		logger.debug("Looking for request mappings in application context: " + getApplicationContext());
	}
	// 根据配置的扫描路径获取所有的bean
	String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
			BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
			getApplicationContext().getBeanNamesForType(Object.class));

	for (String beanName : beanNames) {
		// 检查该bean是否是handler
		if (isHandler(getApplicationContext().getType(beanName))){
			detectHandlerMethods(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

// 通过@Controller或@RequestMapping来判断是否是handler
protected boolean isHandler(Class beanType) {
	return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
			(AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
}

// 检测handler方法并注册
protected void detectHandlerMethods(final Object handler) {
	Class handlerType = (handler instanceof String) ?
			getApplicationContext().getType((String) handler) : handler.getClass();

	final Class userType = ClassUtils.getUserClass(handlerType);

	Set methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
		public boolean matches(Method method) {
			return getMappingForMethod(method, userType) != null;
		}
	});

	for (Method method : methods) {
		// 获取匹配该处理方法的条件信息
		T mapping = getMappingForMethod(method, userType);
		registerHandlerMethod(handler, method, mapping);
	}
}

// 获取匹配该处理方法的条件信息,RequestMappingInfo是满足该方法的条件信息,包括多个具体条件RequestCondition(可自定义实现)
protected RequestMappingInfo getMappingForMethod(Method method, Class handlerType) {
	RequestMappingInfo info = null;
	RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
	if (methodAnnotation != null) {
		RequestCondition methodCondition = getCustomMethodCondition(method);
		info = createRequestMappingInfo(methodAnnotation, methodCondition);
		RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
		if (typeAnnotation != null) {
			RequestCondition typeCondition = getCustomTypeCondition(handlerType);
			info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
		}
	}
	return info;
}

// 注册处理方法
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
	HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
	HandlerMethod oldHandlerMethod = handlerMethods.get(mapping);
	if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
		throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean()
				+ "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '"
				+ oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
	}
	// 以满足该处理方法的条件为key
	this.handlerMethods.put(mapping, newHandlerMethod);
	if (logger.isInfoEnabled()) {
		logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
	}

	Set patterns = getMappingPathPatterns(mapping);
	for (String pattern : patterns) {
		if (!getPathMatcher().isPattern(pattern)) {
			this.urlMap.add(pattern, mapping);
		}
	}
}

以下是根据请求去匹配对应处理方法的相关源码

// 获取处理方法
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	Object handler = getHandlerInternal(request);
	
	......
}

// 获取请求路径,根据请求路径去获取处理方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	if (logger.isDebugEnabled()) {
		logger.debug("Looking up handler method for path " + lookupPath);
	}

	HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

	......
}

// 根据请求路径去获取处理方法
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	// 匹配到的结果集
	List matches = new ArrayList();
	// 根据路径直接等值匹配获取
	List directPathMatches = this.urlMap.get(lookupPath);
	if (directPathMatches != null) {
		addMatchingMappings(directPathMatches, matches, request);
	}

	if (matches.isEmpty()) {
		// 遍历所有注册的处理方法条件去做匹配
		addMatchingMappings(this.handlerMethods.keySet(), matches, request);
	}

	if (!matches.isEmpty()) {
		Comparator comparator = new MatchComparator(getMappingComparator(request));
		Collections.sort(matches, comparator);

		if (logger.isTraceEnabled()) {
			logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
		}

		Match bestMatch = matches.get(0);
		if (matches.size() > 1) {
			Match secondBestMatch = matches.get(1);
			if (comparator.compare(bestMatch, secondBestMatch) == 0) {
				Method m1 = bestMatch.handlerMethod.getMethod();
				Method m2 = secondBestMatch.handlerMethod.getMethod();
				throw new IllegalStateException(
						"Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
						m1 + ", " + m2 + "}");
			}
		}

		handleMatch(bestMatch.mapping, lookupPath, request);
		return bestMatch.handlerMethod;
	}
	else {
		return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
	}
}

private void addMatchingMappings(Collection mappings, List matches, HttpServletRequest request) {
	for (T mapping : mappings) {
		// 根据条件信息和请求获得匹配结果,结果不为null则匹配成功
		T match = getMatchingMapping(mapping, request);
		if (match != null) {
			// 添加到匹配结果集中
			matches.add(new Match(match, handlerMethods.get(mapping)));
		}
	}
}

protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
	// 调用该条件的匹配方法去匹配请求,返回匹配结果
	return info.getMatchingCondition(request);
}


2、相关扩展
(1)继承RequestMappingHandlerMapping,覆盖下面的两个方法,返回自定义的RequestCondition,可以控制判断请求与处理方法是否匹配
protected RequestCondition getCustomTypeCondition(Class handlerType) {
    return null;
}
protected RequestCondition getCustomMethodCondition(Method method) {
    return null;
}

 

3、收到请求查找对应@RequestMapping处理方法
(1)相关类
DispatcherServlet 入口类

(2)DispatcherServlet源码解析

以下分析只是关注如何获取到上面分析的RequestMappingHandlerMapping中注册的处理方法

// 初始化相关策略,当然这里初始化了HandlerMapping
protected void initStrategies(ApplicationContext context) {
	initMultipartResolver(context);
	initLocaleResolver(context);
	initThemeResolver(context);
	initHandlerMappings(context);
	initHandlerAdapters(context);
	initHandlerExceptionResolvers(context);
	initRequestToViewNameTranslator(context);
	initViewResolvers(context);
	initFlashMapManager(context);
}

// 初始化了HandlerMapping
private void initHandlerMappings(ApplicationContext context) {
	this.handlerMappings = null;

	if (this.detectAllHandlerMappings) {
		// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
		Map matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.handlerMappings = new ArrayList(matchingBeans.values());
			// We keep HandlerMappings in sorted order.
			OrderComparator.sort(this.handlerMappings);
		}
	}
	else {
		try {
			HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
			this.handlerMappings = Collections.singletonList(hm);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Ignore, we'll add a default HandlerMapping later.
		}
	}

	// Ensure we have at least one HandlerMapping, by registering
	// a default HandlerMapping if no other mappings are found.
	if (this.handlerMappings == null) {
		this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
		if (logger.isDebugEnabled()) {
			logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
		}
	}
}
		
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// HandlerMapping的实现类就是上面提到的RequestMappingHandlerMapping
	for (HandlerMapping hm : this.handlerMappings) {
		if (logger.isTraceEnabled()) {
			logger.trace(
					"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		// 这里就回到了上面RequestMappingHandlerMapping中根据请求去匹配对应处理方法的分析了,整个流程就连接上了。
		HandlerExecutionChain handler = hm.getHandler(request);
		if (handler != null) {
			return handler;
		}
	}
	return null;
}

 

你可能感兴趣的:(spring,springmvc)