首先,我们在AnnotationDrivenBeanDefinitionParser中会实例化一个RequestMappingHandlerMapping实例,然后向Spring容器中注册这个实例。
查看其父类可知,实现了InitializingBean接口。所以在实例化后会调用afterPropertiesSet方法
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
由此可见这个方法是用来在实例化时探测handler方法
/**
* Detects handler methods at initialization.
*/
public void afterPropertiesSet() {
initHandlerMethods();
}
扫描ApplicationContext中的bean,探测和注册handler method
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
//...根据BeanFactory中存放的Bean的类型,找到所有的注册Bean
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
//根据RequestMapping或者Controller注解判断是不是Handler
if (isHandler(getApplicationContext().getType(beanName))){
detectHandlerMethods(beanName);//探测
}
}
handlerMethodsInitialized(getHandlerMethods());
}
根据Method上的RequestMapping注解查找一个Handler中的handler方法
/**
* Look for handler methods in a handler.
* @param handler the bean name of a handler or a handler instance
*/
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String) ?//判定是不是字符串,是则根据根据字符串获得其对应的类名
getApplicationContext().getType((String) handler) : handler.getClass();
final Class<?> userType = ClassUtils.getUserClass(handlerType);//判定是不是自定义的
//根据一个方法过滤器获得被RequestMapping注解标记的Method
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
public boolean matches(Method method) {
return getMappingForMethod(method, userType) != null;
}
});
for (Method method : methods) {遍历这个method集合,所以可知,每一个Method都会有对应的MappingInfo与之对应
T mapping = getMappingForMethod(method, userType);//根据Method和类获取MappingInfo
//将返回的RequestMappingInfo注册到RequestMappingHandlerMapping上
registerHandlerMethod(handler, method, mapping);
}
}
使用方法和类级别的注解去创建一个RequestMappingInfo
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = null;//寻找方法上的RequestMapping注解,返回RequestMapping注解
RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
if (methodAnnotation != null) {
RequestCondition<?> methodCondition = getCustomMethodCondition(method);//一个空的实现
info = createRequestMappingInfo(methodAnnotation, methodCondition);//创建一个RequestMappingInfo
RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
if (typeAnnotation != null) {//虚招类上的RequestMapping注解,如果有,则进行组合操作
RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);//空的实现
info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);//组合MethodInfo
}
}
return info;//返回这个RequestMappingInfo
}
需要详细对RequestMappingInfo这个类进行分析,特别是其combine方法和里面的几个重要的属性。
protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation,
RequestCondition<?> customCondition) {
String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
return new RequestMappingInfo(
new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
new RequestMethodsRequestCondition(annotation.method()),
new ParamsRequestCondition(annotation.params()),
new HeadersRequestCondition(annotation.headers()),
new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
new ProducesRequestCondition(annotation.produces(), annotation.headers(),
getContentNegotiationManager()),
customCondition);
}
将返回的RequestMappingInfo注册到RequestMappingHandlerMapping上,其中两个重要的属性handlerMethods以及urlMap。使用HandlerMethod是可以理解的,因为在调用Method时肯定需要传入一个instance实例才行,而handler则对应这个实例。所以将这两个封装在一个对象里,方便传递。
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);//方法内部直接new出一个HandlerMethod对象
//handlerMethods用来存放RequestMappingInfo与HandlerMethod的键值对 ,
HandlerMethod oldHandlerMethod = handlerMethods.get(mapping);
//如果本来就已经存在不相同的HandlerMethod则抛出异常
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.");
}
//将RequestMappingInfo与HandlerMethod放入handlerMethods属性中
this.handlerMethods.put(mapping, newHandlerMethod);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
}
//从RequestMappingInfo中获得一个pattern集合,就是ReqeustMapping注解的value值。。
Set<String> patterns = getMappingPathPatterns(mapping);
for (String pattern : patterns) {
if (!getPathMatcher().isPattern(pattern)) {
//将这个pattern与RequestMappingInfo关联起来,以便以后根据url进行匹配找到MappingInfo,再根据MappingInfo找到HandlerMethod
this.urlMap.add(pattern, mapping);
}
}
}
至此可以知道初始化RequestMappingHandlerMapping时是将所有用ReqeustMapping标记的类和方法包装在一个HandlerMethod中,然后将其与RequestMappingInfo进行配对,并存入RequestMappingHandlerMapping的handlerMethods中。将pattern与RequestMappingInfo进行配对,存入RequestMappingHandlerMapping的urlMap中。可以预测,在servlet提供服务时,会根据requestPath匹配对应的url,进而得到HandlerMethod,处理具体业务。