持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情
[SpringMvc 将@RequestMapping注册到HandlerMapping]
@Controller 以及 @RequestMapping是如何被url请求映射到并且执行的?
适配器模式
HandlerAdapter 接口.
对于不同的Controller(org.springframework.web.servlet.mvc.Controller)类用不同的Handler进行处理 各个controller对应的handler都实现了 HandlerAdapter,
RequestMappingHandlerAdapter implements HandlerAdapter
处理加了注解的@Controller类
整体思路
Spring Mvc通过HandlerMapping返回执行链。在Spring容器中有多中不同的HandlerMapping实现,其对应不同的映射配置方式。在使用@RequestMapping注解时,SpringMvc通过RequestMappingHandlerMapping类的Bean解析、注册、缓存映射关系,并提供匹配执行链的功能。
RequestMappingHandlerMapping
1 解析 url-method 映射关系 思路
RequestMappingHandlerMapping实现了InitializingBean接口,在其初始化时执行afterPropertiesSet方法。在此方法中其遍历ApplicationContext中所有Bean,通过反射判断其类型Class上是否有@Controller或@RequestMapping注解。
若Class上有此类注解说明这个Bean是Controller。则执行detectHandlerMethods(beanName)方法,反射(clazz.getMethods())并遍历此Bean的Method[],通过反射method.getAnnotation(RequestMapping)判断并获取方法上标注的@RequestMapping配置信息。将@RequestMapping信息封装成RequestMappingInfo,将此method封装成HandlerMethod。注册到RequestMappingHandlerMapping的mappingRegistry中。
2 注册并缓存 url-method 映射关系
RequestMappingHandlerMapping中的mappingRegistry对象中成员变量:各种Map还有一个读写锁。
mappingRegistry的各个主要变量
3 接收请求在RequestMappingHandlerMapping中查找返回映射
通过request的请求URL从urlLookup中找到对应RequestMappingInfo,再通过RequestMappingInfo在mappingLookup中找到HandlerMethod。HandlerMethod为url对应的@RequestMapping标注执行方法。
解析注册具体实现
WebConfig上使用了@EnableWebMvc注解,这个注解导入了DelegatingWebMvcConfiguration配置,在DelegatingWebMvcConfiguration的父类WebMvcConfigurationSupport创建了RequestMappingHandlerMapping。
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); //...省略属性设置 return mapping;
}
RequestMappingHandlerMapping的父类实现了InitializingBean,那么在初始化的时候就会调用afterPropertiesSet方法。看下父类afterPropertiesSet的实现:
@Override public void afterPropertiesSet() { initHandlerMethods(); } protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } //detectHandlerMethodsInAncestorContexts默认false,所以是得到所有的beanNames String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null; try { beanType = getApplicationContext().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); } } //2. isHandler由子类实现 if (beanType != null && isHandler(beanType)) { //3. 查找controller中有@RequestMapping注解的方法,并注册到请求 detectHandlerMethods(beanName); } } } //空方法 handlerMethodsInitialized(getHandlerMethods()); }
afterPropertiesSet实现交给了initHandlerMethods,initHandlerMethods的执行流程如下:
1. 得到所有的beanName
1. 遍历beanNames,调用isHandler判断bean是不是一个controller,isHandler由子类实现,RequestMappingHandlerMapping的实现如下,判断bean中有没有Controller或RequestMapping
@Override protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
1. 查找controller中有@RequestMapping注解的方法,并注册到请求容器中
protected void detectHandlerMethods(final Object handler) { //1. 得到controller真实类型 Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); final Class<?> userType = ClassUtils.getUserClass(handlerType); //3. 封装所有的Method和RequestMappingInfo到Map中 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, new MethodIntrospector.MetadataLookup<T>() { @Override public T inspect(Method method) { try { //2. 根据方法上的@RequestMapping信息构建RequestMappingInfo return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } } }); if (logger.isDebugEnabled()) { logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods); } for (Map.Entry<Method, T> entry : methods.entrySet()) { Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType); T mapping = entry.getValue(); //4. 将RequestMappingInfo注册到请求容器中 registerHandlerMethod(handler, invocableMethod, mapping); } }
detectHandlerMethods是加载请求核心方法,执行流程如下:
(1) 得到controller真实类型,controller可能被代理
(2) 根据方法上的@RequestMapping信息构建RequestMappingInfo,由RequestMappingHandlerMapping实现。从代码上可以看出,必须方法上声明@RequestMapping,类上的@RequestMapping才会生效。
@Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { //1. 根据方法上的@RequestMapping创建RequestMappingInfo RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { //2. 查找类上是否有@RequestMapping,如果有则和方法上的组合 RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { info = typeInfo.combine(info); } } return info; }
1. 封装所有的Method和RequestMappingInfo到Map中
1. 将RequestMappingInfo注册到请求容器中
protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); }
这里就不再分析register方法的实现过程,主要是根据handler,method封装成HandlerMethod,再请求的时候会得到HandlerMethod,然后反射调用。