SpringMvc中对 @RequestMapping注解的处理流程可以分为下面6步:
1.注册RequestMappingHandlerMapping bean
在AnnotationDrivenBeanDefinitionParser类的parse()方法中:
@Override
public BeanDefinition parse(Element element, ParserContext context) {
Object source = context.extractSource(element);
XmlReaderContext readerContext = context.getReaderContext();
//生成RequestMappingHandlerMapping bean信息
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
//此处HANDLER_MAPPING_BEAN_NAME值为:RequestMappingHandlerMapping类名
//容器中注册name为RequestMappingHandlerMapping类名
context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
}
可以看到上面方法在Spring MVC容器中注册了一个名为“HANDLER_MAPPING_BEAN_NAME”的bean。
2.实例化RequestMappingHandlerMapping bean。
进入initHandlerMethods初始化方法查看逻辑:
protected void initHandlerMethods() {
//1.获取容器中所有bean 的name。
//根据detectHandlerMethodsInAncestorContexts bool变量的值判断是否获取父容器中的bean,默认为false。因此这里只获取Spring MVC容器中的bean,不去查找父容器
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
//循环遍历bean
for (String beanName : beanNames) {
//2.判断bean是否含有@Controller或者@RequestMappin注解
if (beanType != null && isHandler(beanType)) {
//3.对含有注解的bean进行处理,获取handler函数信息。
detectHandlerMethods(beanName);
}
}
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
(1)获取Spring MVC容器中的bean。 (2)找出含有含有@Controller或者@RequestMappin注解的bean。 (3)对含有注解的bean进行解析。
查看detectHandlerMethods()方法。
protected void detectHandlerMethods(final Object handler) {
//1.获取bean的类信息
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//2.遍历函数获取有@RequestMapping注解的函数信息
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
//如果有@RequestMapping注解,则获取函数映射信息
return getMappingForMethod(method, userType);
}
});
//3.遍历映射函数列表,注册handler
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
//注册handler函数
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
看看createRequestMappingInfo是如何实现的。
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, RequestCondition<?> customCondition) {
return RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name())
.customCondition(customCondition)
.options(this.config)
.build();
}
可以看到上面把RequestMapping注解中的信息都放到一个RequestMappingInfo实例中后返回。 当生成含有@RequestMapping注解的函数映射信息后,最后一步是调用registerHandlerMethod 注册handler和处理函数映射关系。
3.获取RequestMappingHandlerMapping bean实例。
initHandlerMappings方法中:
private void initHandlerMappings(ApplicationContext context) {
//容器中查找name为"ANDLER_MAPPING_BEAN_NAME"的实例
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
//把找到的bean放到hanlderMappings中。
this.handlerMappings = Collections.singletonList(hm);
}
进入initHandlerMappings()方法。 此处我们看到从容器中获取了name为 “HANDLER_MAPPING_BEAN_NAME”的bean,这个bean大家应该还记得吧,就是前面注册并实例化了的HandlerMapping bean。