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());
}