- RequestMappingHandlerMapping继承于RequestMappingInfoHandlerMapping继承于AbstractHandlerMethodMapping,其中AbstractHandlerMethodMapping系列是将method作为handler来使用的,比如@RequestMapping所注释的方法就是这种handler。AbstractHandlerMethodMapping里涉及的三个map。
/* java
private final Map<T,HandlerMethod> handlerMethods = new LinkedHashMap<T,HandlerMethod>();
private final MultiValueMap<String,T> urlMap = new LinkedMultiValueMap<String,T>();
private final MultiValueMap<String,HandlerMethod> nameMap = new LinkedMultiValueMap<String,HandlerMethod>();
*/
- handlerMethods:保存着匹配条件(也就是RequestCondition)和Handler Method的对应关系,
- urlMap:保存着URL与匹配条件的对应关系,当然这里的URL是pattern式的,可以使用通配符,另外,这里的map并不是普通的map,而是MultiValueMap,这是一种一个key对应多个值的Map,其实它的value是一个list类型的值。MultiValueMap的定义如下:public interface MultiValueMap<K,V> extends Map<K,List<V>>,这里的RequestCondition其实就是在@RequestMapping中注释的内容。
- nameMap:这个Map是Spring MVC4新增的,保存着name和HandlerMethod的对应关系,它使用的是MultiValueMap类型的Map,也就是说一个name可以有多个HandlerMethod,这里的name是使用HandlerMethodMappingNamingStrategy策略的实现类从HandlerMethod中解析出来,默认使用RequestMappingInfoHandlerMethodMappingNamingStrategy实现类,解析规则是:类名里的大写字母+“#”+方法名
。
- AbstractHandlerMethodMapping系列的创建过程是:AbstractHandlerMethodMapping实现了InitializingBean接口,所以Spring容器会自动调用其afterPropertiesSet方法,afterPropertiesSet有交给initHandlerMethods方法完成具体的初始化。
/* Java
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
*/
- 首先拿到容器里所有的bean,然后跟住一定的规则筛选出来Handler,然后保存在map里,具体的筛选是在子类里,筛选的逻辑是检查类前是否有@Controller或者@RequestMapping注解。
紧接着,在detectHandlerMethods负责将Handler保存在Map里,detectHandlerMethods方法分两步走:首先从传入的处理器中找到符合要求的方法,然后用registerHandlerMethod进行注册(也就是保存在Map中),从这里可以看出Spring其实是将处理请求的方法所在的类看作处理器,而不是处理请求的方法,不过许多地方需要将请求的方法作为处理器来理解。从handler里获取可以处理请求的method的方法使用了HandlerMethodSelector.selectMethods,这个方法可以遍历传入的handler的所有方法,然后根据第二个MethodFilter类型的参数筛选出来合适的方法,这里的MethodFilter使用了匿名类,具体的判断逻辑是通过在匿名类里调用getMappingForMethod方法获取Method的匹配条件,如果可以获取,则认为是符合要求的,否则不符合要求,getMappingForMethod是模版方法,具体实现在RequestMappingHandlerMapping里,它是根据@RequestMapping注解来【匹配条件的,如果没有@RequestMapping注解则返回null,如果有,则根据注解的内容来创建RequestMappingInfo类型的匹配条件并返回。最后通过registerHandlerMethod的方法,注册到map中,在该方法中,首先检查一下handlerMethods这个map里是否已经有这个匹配条件了,如果有而且所对应的值和现在传入的handlerMethod不是同一个则抛出异常,否者依次添加到三个map里,再往nameMap里添加的时候需要现解析出name然后调用updateNameMap方法进行添加,通过put方法,进行覆盖式添加。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。