RequestMappingHandlerMapping
简介
RequestMappingHandlerMapping是AbstractHandlerMethodMapping 抽象类的唯一实现类,它的作用 是根据在Controller中的@RequestMapping注解生成RequestMappingInfo。
方法
上一篇在记录AbstractHandlerMethodMapping源码是有出现过一些方法,AbstractHandlerMethodMapping是抽象类这些方法的具体实现都在子类RequestMappingHandlerMapping 中。
detectHandlerMethods
AbstractHandlerMethodMapping#detectHandlerMethods() 这个方法的作用是从handler中获取handler method并注册。detectHandlerMethods 有些方法是需要RequestMappingHandlerMapping 实现的,相关方法会在下面介绍。
/** * 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 ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { //为给定的类返回用户定义的类:通常只是给定的类,如果是cglib生成的子类,则返回原始的类。 final Class<?> userType = ClassUtils.getUserClass(handlerType); Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { // 为处理程序方法提供映射 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); } // 为查找到的handler method 进行注册 methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } }
afterPropertiesSet
初始化bean是调用的方法,各种配置设置并调用父类afterPropertiesSet 方法。
@Override public void afterPropertiesSet() { // 各种配置设置 this.config = new RequestMappingInfo.BuilderConfiguration(); this.config.setUrlPathHelper(getUrlPathHelper()); this.config.setPathMatcher(getPathMatcher()); this.config.setSuffixPatternMatch(this.useSuffixPatternMatch); this.config.setTrailingSlashMatch(this.useTrailingSlashMatch); this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch); this.config.setContentNegotiationManager(getContentNegotiationManager()); // 调用AbstractHandlerMethodMapping afterPropertiesSet 方法 super.afterPropertiesSet(); }
isHandler
isHandler 方法作用是判断提供的handler是否有@Controller或@RequestMapping注解
/** * {@inheritDoc} * <p>Expects a handler to have either a type-level @{@link Controller} * annotation or a type-level @{@link RequestMapping} annotation. */ @Override protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
getMappingForMethod
通过@RequestMapping 注解生成一个RequestMappingInfo 对象并返回,如果没有使用RequestMapping 注解会返回null,主要还是看createRequestMappingInfo 方法
@Override @Nullable protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { info = typeInfo.combine(info); } } return info; }
createRequestMappingInfo
createRequestMappingInfo 解析RequestMapping 注解 生成RequestMappingInfo对象。
createRequestMappingInfo(AnnotatedElement element)这个方法会先判断参数类型,然后根据类型去查找是否有额外的请求条件,如果有就把条件RequestMapping 和 条件做为参数调用重载方法
createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition);
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); // getCustomTypeCondition 和 getCustomMethodCondition return null RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element)); return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); }
getCustomTypeCondition和getCustomMethodCondition 这两个方法没有实现,它们的作用是自定义请求参数条件,如果需要可以继承AbstractRequestCondition 和使用CompositeRequestCondition 类来提供多个自定义条件。
重载方法createRequestMappingInfo,实际生成RequestMappingInfo 的方法,
/** * Create a {@link RequestMappingInfo} from the supplied * {@link RequestMapping @RequestMapping} annotation, which is either * a directly declared annotation, a meta-annotation, or the synthesized * result of merging annotation attributes within an annotation hierarchy. */ protected RequestMappingInfo createRequestMappingInfo( RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) { RequestMappingInfo.Builder builder = RequestMappingInfo .paths(resolveEmbeddedValuesInPatterns(requestMapping.path())) .methods(requestMapping.method()) .params(requestMapping.params()) .headers(requestMapping.headers()) .consumes(requestMapping.consumes()) .produces(requestMapping.produces()) .mappingName(requestMapping.name()); if (customCondition != null) { builder.customCondition(customCondition); } return builder.options(this.config).build(); }
上面就是简单的介绍了一下springmvc路径映射过程,有兴趣的还是看下源码吧,
能力有限,水平一般,如有错误,请多指出。