springMVC分析-2

springMVC的请求映射

上一次分析了一下springMVC的大致流程,这次细分一下,对请求映射进行分析。
先从DispatcherServlet中的getHandler()方法分析

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	for (HandlerMapping hm : this.handlerMappings) {
		if (logger.isTraceEnabled()) {
			logger.trace(
					"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		HandlerExecutionChain handler = hm.getHandler(request);
		if (handler != null) {
			return handler;
		}
	}
	return null;
}

可以看到这是遍历所有的handlerMappings然后第一个返回不是NULL的handler既是,那handlerMappings包含了那些实现类呢?我们来看看initHandlerMappings这个方法

private void initHandlerMappings(ApplicationContext context) {
	this.handlerMappings = null;
	//detectAllHandlerMappings 默认是true
	if (this.detectAllHandlerMappings) {
		// 从ApplicationContext 里面获取HandlerMapping的实现类
		Map<String, HandlerMapping> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
		//根据Order对HandlerMappings进行排序
		if (!matchingBeans.isEmpty()) {
			this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
			// We keep HandlerMappings in sorted order.
			AnnotationAwareOrderComparator.sort(this.handlerMappings);
		}
	}
	else {
		try {
			//获取bean name是handlerMapping的HandlerMapping实现类
			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.
		}
	}

	//若HandlerMappings为空,则设置默认的在DispatcherServlet同级目录下的DispatcherServlet.properties里面设置的
	org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
	if (this.handlerMappings == null) {
		this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
		if (logger.isDebugEnabled()) {
			logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
		}
	}
}

所以若我们想使用自定义的HandlerMapping 可在springMVC的xml配置文件中加上一个HandlerMapping的实现类,若是使用的是<mvc:annotation-driven > 这个进行配置的,其默认会加载RequestMappingHandlerMapping这个实现类(具体在org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser见),而可以在web.xml中将detectAllHandlerMappings 设置为false,然后在springMVC.xml中配置一个name为handlerMapping的实现类。如下

// web.xml
<servlet>
	<servlet-name>myweb</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:mvc.xml</param-value>
	</init-param>
	<!-- 不加载所有的HandlerMapping的实现类的bean -->
	<init-param>
		<param-name>detectAllHandlerMappings</param-name>
		<param-value>false</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

//mvc.xml
<bean name="handlerMapping" class="xxx具体实现类">

继续看handlerMapping是怎么根据request获取到HandlerExecutionChain这个包含拦截器、具体处理的controller的,在AbstractHandlerMapping中以下方法

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//获取具体的处理类
	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 = getApplicationContext().getBean(handlerName);
	}
	//根据定义的Interceptors过滤出需要执行的拦截器,聚合成HandlerExecutionChain这个执行链
	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
	//CORS跨域请求
	if (CorsUtils.isCorsRequest(request)) {
		CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}
	return executionChain;
}

看getHandlerInternal(request) 这个方法,这个方法是个抽象方法,所以其实现在它的子类中,可以看出这个是一个模板模式,其在抽象类中定义出方法的骨架,而后某些方法交给子类实现,这个方法有两个实现类,AbstractHandlerMethodMapping,AbstractUrlHandlerMapping 这两个具体实现类,我们先看AbstractHandlerMethodMapping 这个类实现的

/**
 * Look up a handler method for the given request.
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	//获取请求路径
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	if (logger.isDebugEnabled()) {
		logger.debug("Looking up handler method for path " + lookupPath);
	}
	//开启读锁
	this.mappingRegistry.acquireReadLock();
	try {
		//获取handlerMethod
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		if (logger.isDebugEnabled()) {
			if (handlerMethod != null) {
				logger.debug("Returning handler method [" + handlerMethod + "]");
			}
			else {
				logger.debug("Did not find handler method for [" + lookupPath + "]");
			}
		}
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		//释放锁
		this.mappingRegistry.releaseReadLock();
	}
}

从这里可以看出 其最后处理的是一个HandlerMethod类,我们来看看这个类的结构

public class HandlerMethod {

	private final Object bean;

	private final BeanFactory beanFactory;

	private final Class<?> beanType;

	private final Method method;

	private final Method bridgedMethod;

	private final MethodParameter[] parameters;

	private final HandlerMethod resolvedFromHandlerMethod;
}

可以看出其是一个聚合的类,里面包含了bean,method,故而其可以一个方法对应一个请求。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	List<Match> matches = new ArrayList<Match>();
	//根据请求路径匹配
	List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
	if (directPathMatches != null) {
		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<Match> 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) {
			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();
				throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
						request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
			}
		}
		返回handlerMethod
		handleMatch(bestMatch.mapping, lookupPath, request);
		return bestMatch.handlerMethod;
	}
	else {
		return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
	}
}

AbstractHandlerMethodMapping 这个抽象类实现了InitializingBean接口,所以我们可以看看afterPropertiesSet()方法,其在实例化进行的初始化操作,initHandlerMethods()方法,可以看出其在初始化时,就初始化了HandlerMethod这个。

protected void initHandlerMethods() {
	// 获取所有的Bean
	String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
			BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
			getApplicationContext().getBeanNamesForType(Object.class));

	for (String name : beanNames) {
		//判断这个bean是否包含Controller,和RequestMapping这两个注解
		if (!name.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(name))) {
			//将其注册到MappingRegistry
			detectHandlerMethods(name);
		}
	}
	//空方法
	handlerMethodsInitialized(getHandlerMethods());
}
posted on 2016-03-23 10:55  liaozq  阅读(146)  评论(0编辑  收藏  举报