SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化
2016-02-23 11:22
676 查看
RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping来定义controller.
初始化时,3个类的大致分工如下:
AbstractHandlerMethodMapping定义整个算法流程;
RequestMappingInfoHandlerMapping提供匹配条件RequestMappingInfo的解析处理;
RequestMappingHandlerMapping根据@RequestMapping注解生成 RequestMappingInfo,同时提供isHandler实现
整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods主导.
1. 使用BeanFactoryUtils扫描应用下的Object或者直接从容器中获取Object
2. 迭代类,分别判断isHandler判断目标类是否Handler
2.1 RequestMappingHandlerMapping.isHandler根据@Controller或@RequestMapping注解判断(有任意一个)
3. 对handler解析出所有需要分发的方法detectHandlerMethods
3.1 获取原始的Class<?>
3.2 使用HandlerMethodSelector.selectMethods过滤具体handler method,预留getMappingForMethod模板方法给子类
RequestMappingHandlerMapping.getMappingForMethod根据类,方法上的RequestMapping注解生成匹配条件RequestMappingInfo
3.3 对过滤到的每个method进行注册registerHandlerMethod
a, 使用createHandlerMethod封装处理器为HandlerMethod
b, 判断之前是否已经匹配条件对应的处理器是否冲突(相同的匹配条件只能有一个对应的处理器)
c, 设置匹配条件到handler method的映射关系
d, 从匹配条件中解析出url,并注册到urlMap(url到匹配条件的映射),这边由RequestMappingInfoHandlerMapping.getMappingPathPatterns实现
4. 对HandlerMethod进行初始化handlerMethodsInitialized,其实现在什么都没做
在讲初始化之前,我们先来聊聊使用到的一些概念
1. 映射关系,url到匹配条件RequestMappingInfo,匹配条件到HandlerMethod
2. 特殊的MultiValueMap,特别在value是个List
3. 使用到注解@Controller,@RequestMapping
4. 封装处理器信息的HandlerMethod
5. 封装各类匹配条件的RequestMappingInfo(诸如pattern,http method,request parameter等)
6. RequestCondition记录匹配条件
1. 进行request分发前,需要在初始化时准备好映射关系,这边AbstractHandlerMethodMapping中有两个属性保存了映射关系
// AbstractHandlerMethodMapping
2. 这边的MultiValueMap其实挺简单,就是map的值是个list
3. 我们再来看看这边使用到的两个注解:
// @Controller
// @RequestMapping
4. HandlerMethod封装了处理器相关的全部信息,如类Object,方法Method,BeanFactory,参数MethodParameter[],原始方法Method
// HandlerMethod
5. 这边匹配条件的范型只有一个实现,RequestMappingInfo.匹配条件里记录的是RequestCondition子类,用于诸如pattern,http method,request parameter等
// RequestMappingInfo
6. 最后再简单看看RequestCondition ,这边定义了3个方法
看看继承体系吧,老套路,定义接口,然后模板方法实现主要逻辑,具体算法留给子类实现,还有正事要做,还是后期再细化吧.
正文
整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods主导.copy一段,省得回去比对看
1. 使用BeanFactoryUtils扫描应用下的Object或者直接从容器中获取Object
2. 迭代类,分别判断isHandler判断目标类是否Handler
2.1 RequestMappingHandlerMapping.isHandler根据@Controller或@RequestMapping注解判断(有任意一个)
3. 对handler解析出所有需要分发的方法detectHandlerMethods
3.1 获取原始的Class<?>
3.2 使用HandlerMethodSelector.selectMethods过滤具体handler method,预留getMappingForMethod模板方法给子类
RequestMappingHandlerMapping.getMappingForMethod根据类,方法上的RequestMapping注解生成匹配条件RequestMappingInfo
3.3 对过滤到的每个method进行注册registerHandlerMethod
a, 使用createHandlerMethod封装处理器为HandlerMethod
b, 判断之前是否已经匹配条件对应的处理器是否冲突(相同的匹配条件只能有一个对应的处理器)
c, 设置匹配条件到handler method的映射关系
d, 从匹配条件中解析出url,并注册到urlMap(url到匹配条件的映射),这边由RequestMappingInfoHandlerMapping.getMappingPathPatterns实现
4. 对HandlerMethod进行初始化handlerMethodsInitialized,其实现在什么都没做
// AbstractHandlerMethodMapping
预留给子类实现的判断handler,实际是由RequestMappingHandlerMapping实现
// AbstractHandlerMethodMapping
// RequestMappingHandlerMapping
这边判断的逻辑很简单,类上使用Controller或RequestMapping其中至少一个注解就可以.
// AbstractHandlerMethodMapping
// AbstractHandlerMethodMapping
这边具体的实现是由RequestMappingHandlerMapping实现,根据注解生产匹配关系,这边实现类是RequestMappingInfo,就是代码有点多,慢慢看
// RequestMappingHandlerMapping
// RequestMappingHandlerMapping
// AbstractHandlerMethodMapping
// AbstractHandlerMethodMapping
// AbstractHandlerMethodMapping
RequestMappingInfoHandlerMapping会实现这个模板方法
// RequestMappingInfoHandlerMapping
备注:
1. 这边的afterPropertiesSet是因为实现了InitializingBean接口
// org.springframework.beans.factory.InitializingBean
@Controller @RequestMapping(value = "books") public class BookController { @RequestMapping(value = "/{id}") @ResponseBody public String getBook(@PathVariable("id") String id) { // ... return id; } }
初始化时,3个类的大致分工如下:
AbstractHandlerMethodMapping定义整个算法流程;
RequestMappingInfoHandlerMapping提供匹配条件RequestMappingInfo的解析处理;
RequestMappingHandlerMapping根据@RequestMapping注解生成 RequestMappingInfo,同时提供isHandler实现
整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods主导.
1. 使用BeanFactoryUtils扫描应用下的Object或者直接从容器中获取Object
2. 迭代类,分别判断isHandler判断目标类是否Handler
2.1 RequestMappingHandlerMapping.isHandler根据@Controller或@RequestMapping注解判断(有任意一个)
3. 对handler解析出所有需要分发的方法detectHandlerMethods
3.1 获取原始的Class<?>
3.2 使用HandlerMethodSelector.selectMethods过滤具体handler method,预留getMappingForMethod模板方法给子类
RequestMappingHandlerMapping.getMappingForMethod根据类,方法上的RequestMapping注解生成匹配条件RequestMappingInfo
3.3 对过滤到的每个method进行注册registerHandlerMethod
a, 使用createHandlerMethod封装处理器为HandlerMethod
b, 判断之前是否已经匹配条件对应的处理器是否冲突(相同的匹配条件只能有一个对应的处理器)
c, 设置匹配条件到handler method的映射关系
d, 从匹配条件中解析出url,并注册到urlMap(url到匹配条件的映射),这边由RequestMappingInfoHandlerMapping.getMappingPathPatterns实现
4. 对HandlerMethod进行初始化handlerMethodsInitialized,其实现在什么都没做
在讲初始化之前,我们先来聊聊使用到的一些概念
1. 映射关系,url到匹配条件RequestMappingInfo,匹配条件到HandlerMethod
2. 特殊的MultiValueMap,特别在value是个List
3. 使用到注解@Controller,@RequestMapping
4. 封装处理器信息的HandlerMethod
5. 封装各类匹配条件的RequestMappingInfo(诸如pattern,http method,request parameter等)
6. RequestCondition记录匹配条件
1. 进行request分发前,需要在初始化时准备好映射关系,这边AbstractHandlerMethodMapping中有两个属性保存了映射关系
// AbstractHandlerMethodMapping
// 匹配条件到HandlerMethod的映射 private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>(); // url到匹配条件的映射 private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
2. 这边的MultiValueMap其实挺简单,就是map的值是个list
public interface MultiValueMap<K, V> extends Map<K, List<V>> { // ... }
3. 我们再来看看这边使用到的两个注解:
// @Controller
// org.springframework.stereotype.Controller @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any */ String value() default ""; }
// @RequestMapping
// org.springframework.web.bind.annotation.RequestMapping @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping { /** * url路径,如/myPath/*.do */ String[] value() default {}; /** * HTTP request methods 如:GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. */ RequestMethod[] method() default {}; /** * requeset parameter 有3种匹配方式,是否包含某个参数,参数值相等,参数值不等于某个值,如myParam!=myValue */ String[] params() default {}; /** * request的header */ String[] headers() default {}; /** * request的content type */ String[] consumes() default {}; /** * 返回内容的content type */ String[] produces() default {}; } }
4. HandlerMethod封装了处理器相关的全部信息,如类Object,方法Method,BeanFactory,参数MethodParameter[],原始方法Method
// HandlerMethod
// org.springframework.web.method.HandlerMethod private final Object bean;// 因为final不可修改,所以下面每次需要修改信息时,都需要new一个 private final Method method; private final BeanFactory beanFactory; private final MethodParameter[] parameters; private final Method bridgedMethod;
5. 这边匹配条件的范型只有一个实现,RequestMappingInfo.匹配条件里记录的是RequestCondition子类,用于诸如pattern,http method,request parameter等
// RequestMappingInfo
// javax.servlet.http.HttpServletRequest.RequestMappingInfo public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> { private final PatternsRequestCondition patternsCondition; private final RequestMethodsRequestCondition methodsCondition; private final ParamsRequestCondition paramsCondition; private final HeadersRequestCondition headersCondition; private final ConsumesRequestCondition consumesCondition; private final ProducesRequestCondition producesCondition; private final RequestConditionHolder customConditionHolder; // ... }
6. 最后再简单看看RequestCondition ,这边定义了3个方法
package org.springframework.web.servlet.mvc.condition; public interface RequestCondition<T> { /** * 拼接条件 */ T combine(T other); /** * 查找匹配的条件,并返回 */ T getMatchingCondition(HttpServletRequest request); /** * 用于排序 */ int compareTo(T other, HttpServletRequest request); }
看看继承体系吧,老套路,定义接口,然后模板方法实现主要逻辑,具体算法留给子类实现,还有正事要做,还是后期再细化吧.
正文
整个初始化工作由AbstractHandlerMethodMapping的initHandlerMethods主导.copy一段,省得回去比对看
1. 使用BeanFactoryUtils扫描应用下的Object或者直接从容器中获取Object
2. 迭代类,分别判断isHandler判断目标类是否Handler
2.1 RequestMappingHandlerMapping.isHandler根据@Controller或@RequestMapping注解判断(有任意一个)
3. 对handler解析出所有需要分发的方法detectHandlerMethods
3.1 获取原始的Class<?>
3.2 使用HandlerMethodSelector.selectMethods过滤具体handler method,预留getMappingForMethod模板方法给子类
RequestMappingHandlerMapping.getMappingForMethod根据类,方法上的RequestMapping注解生成匹配条件RequestMappingInfo
3.3 对过滤到的每个method进行注册registerHandlerMethod
a, 使用createHandlerMethod封装处理器为HandlerMethod
b, 判断之前是否已经匹配条件对应的处理器是否冲突(相同的匹配条件只能有一个对应的处理器)
c, 设置匹配条件到handler method的映射关系
d, 从匹配条件中解析出url,并注册到urlMap(url到匹配条件的映射),这边由RequestMappingInfoHandlerMapping.getMappingPathPatterns实现
4. 对HandlerMethod进行初始化handlerMethodsInitialized,其实现在什么都没做
// AbstractHandlerMethodMapping
/** 这个方法哪来的,具体看备注的InitializingBean * 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() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { if (isHandler(getApplicationContext().getType(beanName))){ detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }
预留给子类实现的判断handler,实际是由RequestMappingHandlerMapping实现
// AbstractHandlerMethodMapping
/** * Whether the given type is a handler with handler methods. * @param beanType the type of the bean being checked * @return "true" if this a handler type, "false" otherwise. */ protected abstract boolean isHandler(Class<?> beanType);
// RequestMappingHandlerMapping
这边判断的逻辑很简单,类上使用Controller或RequestMapping其中至少一个注解就可以.
/** * {@inheritDoc} * Expects a handler to have a type-level @{@link Controller} annotation. */ @Override protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); }
// AbstractHandlerMethodMapping
/** * 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); Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { public boolean matches(Method method) { return getMappingForMethod(method, userType) != null; } }); for (Method method : methods) { T mapping = getMappingForMethod(method, userType); registerHandlerMethod(handler, method, mapping); } }
// AbstractHandlerMethodMapping
这边具体的实现是由RequestMappingHandlerMapping实现,根据注解生产匹配关系,这边实现类是RequestMappingInfo,就是代码有点多,慢慢看
/** * Provide the mapping for a handler method. A method for which no * mapping can be provided is not a handler method. * @param method the method to provide a mapping for * @param handlerType the handler type, possibly a sub-type of the method's * declaring class * @return the mapping, or {@code null} if the method is not mapped */ protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
// RequestMappingHandlerMapping
/** * Uses method and type-level @{@link RequestMapping} annotations to create * the RequestMappingInfo. * * @return the created RequestMappingInfo, or {@code null} if the method * does not have a {@code @RequestMapping} annotation. * * @see #getCustomMethodCondition(Method) * @see #getCustomTypeCondition(Class) */ @Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = null; // 读取方法上的RequestMapping注解信息 RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (methodAnnotation != null) { // 读取自定义的条件,这边没有使用 RequestCondition<?> methodCondition = getCustomMethodCondition(method); // 根据方法上的RequsetMapping注解和自定义条件,生成匹配条件.这边的匹配条件包括http method,request parameter,request header等 info = createRequestMappingInfo(methodAnnotation, methodCondition); // 读取类上的RequestMapping注解信息 RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); if (typeAnnotation != null) { RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType); // 生成类上的匹配条件,并合并方法上的 info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); } } return info; }
// RequestMappingHandlerMapping
/** * Created a RequestMappingInfo from a RequestMapping annotation. */ private 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); } /** * Resolve placeholder values in the given array of patterns. * @return a new array with updated patterns */ protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) { if (this.embeddedValueResolver == null) { return patterns; } else { String[] resolvedPatterns = new String[patterns.length]; for (int i=0; i < patterns.length; i++) { resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]); } return resolvedPatterns; } }
// AbstractHandlerMethodMapping
/** * Register a handler method and its unique mapping. * @param handler the bean name of the handler or the handler instance * @param method the method to register * @param mapping the mapping conditions associated with the handler method * @throws IllegalStateException if another method was already registered * under the same mapping */ protected void registerHandlerMethod(Object handler, Method method, T mapping) { HandlerMethod newHandlerMethod = createHandlerMethod(handler, method); HandlerMethod oldHandlerMethod = handlerMethods.get(mapping); 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."); } this.handlerMethods.put(mapping, newHandlerMethod);// 匹配条件requestMappingInfo 到处理器HandlerMethod if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod); } Set<String> patterns = getMappingPathPatterns(mapping); for (String pattern : patterns) { if (!getPathMatcher().isPattern(pattern)) { this.urlMap.add(pattern, mapping);// url到匹配条件RequestMappingInfo } } }
// AbstractHandlerMethodMapping
/** * Create the HandlerMethod instance. * @param handler either a bean name or an actual handler instance * @param method the target method * @return the created HandlerMethod */ protected HandlerMethod createHandlerMethod(Object handler, Method method) { HandlerMethod handlerMethod; if (handler instanceof String) { String beanName = (String) handler; handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method); } else { handlerMethod = new HandlerMethod(handler, method); } return handlerMethod; }
// AbstractHandlerMethodMapping
/** * Extract and return the URL paths contained in a mapping. */ protected abstract Set<String> getMappingPathPatterns(T mapping);
RequestMappingInfoHandlerMapping会实现这个模板方法
// RequestMappingInfoHandlerMapping
/** * Get the URL path patterns associated with this {@link RequestMappingInfo}. */ @Override protected Set<String> getMappingPathPatterns(RequestMappingInfo info) { return info.getPatternsCondition().getPatterns(); }
备注:
1. 这边的afterPropertiesSet是因为实现了InitializingBean接口
// org.springframework.beans.factory.InitializingBean
/** * Interface to be implemented by beans that need to react once all their * properties have been set by a BeanFactory: for example, to perform custom * initialization, or merely to check that all mandatory properties have been set. * * <p>An alternative to implementing InitializingBean is specifying a custom * init-method, for example in an XML bean definition. * For a list of all bean lifecycle methods, see the BeanFactory javadocs. * * @author Rod Johnson * @see BeanNameAware * @see BeanFactoryAware * @see BeanFactory * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName * @see org.springframework.context.ApplicationContextAware */ public interface InitializingBean { /** * Invoked by a BeanFactory after it has set all bean properties supplied * (and satisfied BeanFactoryAware and ApplicationContextAware). * <p>This method allows the bean instance to perform initialization only * possible when all bean properties have been set and to throw an * exception in the event of misconfiguration. * @throws Exception in the event of misconfiguration (such * as failure to set an essential property) or if initialization fails. */ void afterPropertiesSet() throws Exception; }
相关文章推荐
- Apple Pay强势来袭,开发者应做的事情(转)
- 简单易懂的Android --NDK环境搭建>基础使用过程
- swift-字符串02-字符串的插值,连接,长度
- ios开发UDP协议发送广播寻找设备
- 整理iOS常用的第三方框架
- ios开发UDP协议发送广播寻找设备
- android布局
- Android 开发小提示集合
- Android 自定义漂亮的圆形进度条
- 在SharePoint Server 2016 RC 中利用ASP.Net SQL MemberShip和Role Provider为Web Application配置Forms-based身份验证
- DJANGO问题--Error: ‘ManyRelatedManager’ object is not iterable
- Swift开发IOS的细节
- 如何在mac本上安装android sdk 避免被墙
- 利用runtime 实现自定义Model归档
- android限制edittext最大行数的方法
- Android学习笔记day4
- iOS的远程消息推送服务。
- iOS 删除已经配置的类库和移除CocoaPods
- ios布局约束
- Android 通过JNI实现守护进程,使得Service服务不被杀死