java|java spring mvc处理器映射器介绍

目录

  • 一、RequestMappingHandlerMapping解析映射简单介绍
  • 二、@RequestMapping解析源码流程
  • 三、@RequestMapping映射源码流程
  • 四、@RequestMapping解析源码
  • 五、@RequestMapping映射源码
【java|java spring mvc处理器映射器介绍】前言:
  • 本文源码基于spring-framework-5.3.10
  • mvcspring源码中的一个子模块!

一、RequestMappingHandlerMapping解析映射简单介绍
  • @RequestMapping通过RequestMappingHandlerMapping进行解析!
  • HandlerMapping是一个根据URL映射到Handler的方法。
  • RequestMappingHandlerMapping是HandlerMapping的一个子类!
  • RequestMappingHandlerMapping他的父类有InitializingBean,所有在spring启动实例化的时候会调用afterPropertiesSet()方法。解析逻辑就在这里。
  • RequestMappingHandlerMapping有俩个过程:解析、映射

二、@RequestMapping解析源码流程
  • 容器加载,调用RequestMappingHandlerMappingafterPropertiesSet()。
  • 调用父类的afterPropertiesSet()方法。
  • 调用initHandlerMethods()方法。
  • 循环每一个Bean,看方法上有@RequestMapping或者@Controller的Bean。
  • 解析HandlerMethods,进行封装RequestMappingInfo。
  • 将封装好的RequestMappingInfo存起来:key为路径,值为mapping(RequestMappingInfo)

三、@RequestMapping映射源码流程
  • 请求进来,调用getHandler方法。
  • 获取当前请求对应的HandlerMethod
  • 通过UrlPathHelper对象,用于来解析从们的request中解析出请求映射路径。
  • 更具路径去pathLookup中找。
  • 上面没找到,从所有的里面找有通配符的。
  • 找到多个进行排序,优先级:? > * > {} >** 。
  • 不为空拿到第一个返回。
  • 如果为空获取默认的。默认还是空的,直接返回null。
  • 封装拦截器,返回。

四、@RequestMapping解析源码
/** * 解析的开始位置。 * 由于实现了InitializingBean,初始化Bean的时候调用这个方法。 * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet() */public void afterPropertiesSet() { this.config = new RequestMappingInfo.BuilderConfiguration(); this.config.setTrailingSlashMatch(useTrailingSlashMatch()); // 尾部斜杠 this.config.setContentNegotiationManager(getContentNegotiationManager()); if (getPatternParser() != null) {this.config.setPatternParser(getPatternParser()); Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,"Suffix pattern matching not supported with PathPatternParser."); } else {this.config.setSuffixPatternMatch(useSuffixPatternMatch()); this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch()); this.config.setPathMatcher(getPathMatcher()); } // 调用父类的afterPropertiesSet方法 super.afterPropertiesSet(); }/** * 父类的afterPropertiesSet方法。 * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet() */public void afterPropertiesSet() { initHandlerMethods(); }/** * 解析@RequestMapping方法 * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods() */protected void initHandlerMethods() { // 获得所有候选beanName—— 当前容器所有的beanName for (String beanName : getCandidateBeanNames()) {// BeanName不是scopedTarget.开头的if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {// *处理候选bean——即解析@RequestMapping和映射路径processCandidateBean(beanName); } } // 解析完所有@RequestMapping的时候调用 handlerMethodsInitialized(getHandlerMethods()); }/** * 处理候选bean——即解析@RequestMapping和映射路径 * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(String) */protected void processCandidateBean(String beanName) { Class beanType = null; try {// 得到当前BeanName得到这个Bean的类型beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) {// An unresolvable bean type, probably from a lazy bean - let's ignore it.if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex); } } // 这一步判断是关键:是否有Controller 或 RequestMapping注解 if (beanType != null && isHandler(beanType)) {// 解析HandlerMethodsdetectHandlerMethods(beanName); }}/** * 解析HandlerMethods * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(Object) */protected void detectHandlerMethods(Object handler) { Class handlerType = (handler instanceof String ?obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) {Class userType = ClassUtils.getUserClass(handlerType); // 循环所有方法Map methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup) method -> {try {// 根据Method得到Mapping映射return getMappingForMethod(method, userType); }catch (Throwable ex) {throw new IllegalStateException("Invalid mapping on handler class [" +userType.getName() + "]: " + method, ex); }}); if (logger.isTraceEnabled()) {logger.trace(formatMappings(userType, methods)); }else if (mappingsLogger.isDebugEnabled()) {mappingsLogger.debug(formatMappings(userType, methods)); }// 遍历每一个方法,这里是所有Bean的所有方法methods.forEach((method, mapping) -> {Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); // pathLookup放入:key为路径,值为mapping(RequestMappingInfo)registerHandlerMethod(handler, invocableMethod, mapping); }); }}/** * 根据Method得到Mapping映射 * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getMappingForMethod(Method, Class) */protected RequestMappingInfo getMappingForMethod(Method method, Class handlerType) { // 如果方法上面有@RequestMapping:解析出RequestMappingInfo // RequestMappingInfo 是用来在请求的时候做匹对的 RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) {// 如果方法上面有@RequestMapping,看看类上面是不是有@RequestMappingRequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); // 类上面也有@RequestMapping那就合并// 比如 类:/user方法:/info 合并为 /user/infoif (typeInfo != null) {info = typeInfo.combine(info); }// 合并前缀5.1新增默认null// 可通过 WebMvcConfigurer#configurePathMatch 进行定制String prefix = getPathPrefix(handlerType); if (prefix != null) {info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info); } } return info; }/** * 创建请求映射信息的外部逻辑 * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.createRequestMappingInfo(AnnotatedElement) */private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { // 获取RequestMapping注解信息 RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); // 获取请求调解:[可扩展], 如果有:该条件会在请求时匹对 RequestCondition condition = (element instanceof Class ?getCustomTypeCondition((Class) element) : getCustomMethodCondition((Method) element)); // 如果有RequestMapping注解,封装成RequestMappingInfo return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); }/** * 创建请求映射信息的内部逻辑 * 源码位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.createRequestMappingInfo(RequestMapping, RequestCondition) */protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition customCondition) { // 将@RequestMapping注解属性的值构建成一个 RequestMappingInfo RequestMappingInfo.Builder builder = RequestMappingInfo//构建路径.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))//构建方法(get还是post等).methods(requestMapping.method())//参数 对应http request parameter.params(requestMapping.params())//头部.headers(requestMapping.headers())//request的提交内容类型content type,如application/json, text/html.consumes(requestMapping.consumes())//指定返回的内容类型的content type,仅当request请求头中的(Accept)类型中包含该指定类型才返回.produces(requestMapping.produces()).mappingName(requestMapping.name()); if (customCondition != null) {builder.customCondition(customCondition); } // 构造RequestMappingInfo:将上面的属性构建成一个个的RequestCondition对象方便在请求的时候组合匹对 return builder.options(this.config).build(); }/** * 得到所有的方法 * 源码位置:org.springframework.core.MethodIntrospector.selectMethods(Class, MetadataLookup) */public static Map selectMethods(Class targetType, final MetadataLookup metadataLookup) { final Map methodMap = new LinkedHashMap<>(); Set> handlerTypes = new LinkedHashSet<>(); Class specificHandlerType = null; //获取原始的class对象 if (!Proxy.isProxyClass(targetType)) {specificHandlerType = ClassUtils.getUserClass(targetType); handlerTypes.add(specificHandlerType); } //获取class的接口 handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType)); //循环我们的class集合 for (Class currentHandlerType : handlerTypes) {final Class targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType); ReflectionUtils.doWithMethods(currentHandlerType, method -> {//获取具体的方法对象Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); /**回调 即解析@RequestMapping 返回RequestMappingInfo* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod(java.lang.reflect.Method, java.lang.Class)*/T result = metadataLookup.inspect(specificMethod); if (result != null) {// 看看有没有桥接方法:泛型实现类jvm会自动生成桥接类Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {//把方法对象作为key,RequestMappingInfo对象作为value保存到map中methodMap.put(specificMethod, result); }}}, ReflectionUtils.USER_DECLARED_METHODS); } return methodMap; }


五、@RequestMapping映射源码
/** * 获取@RequestMapping映射 * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(HttpServletRequest) */public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 获取当前请求对应的HandlerMethod Object handler = getHandlerInternal(request); // 获取默认的handler if (handler == null) {handler = getDefaultHandler(); } // 还是没有handler的时候返回null,404了 if (handler == null) {return null; } // Bean name or resolved handler? // String类型?获取Bean if (handler instanceof String) {String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } // Ensure presence of cached lookupPath for interceptors and others if (!ServletRequestPathUtils.hasCachedPath(request)) {initLookupPath(request); } // 获取拦截器相关的调用链 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (logger.isTraceEnabled()) {logger.trace("Mapped to " + handler); } else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {logger.debug("Mapped to " + executionChain.getHandler()); } if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {CorsConfiguration config = getCorsConfiguration(handler, request); if (getCorsConfigurationSource() != null) {CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request); config = (globalConfig != null ? globalConfig.combine(config) : config); }if (config != null) {config.validateAllowCredentials(); }executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }/** * 获取当前请求对应的HandlerMethod * 源码位置:org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(HttpServletRequest) */protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); try {// 直接调用父类的getHandlerInternal方法return super.getHandlerInternal(request); } finally {ProducesRequestCondition.clearMediaTypesAttribute(request); }}/** * 获取当前请求对应的HandlerMethod---父类的 * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(HttpServletRequest) */protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 通过UrlPathHelper对象,用于来解析从们的request中解析出请求映射路径 String lookupPath = initLookupPath(request); this.mappingRegistry.acquireReadLock(); try {// 通过lookupPath解析最终的handler——HandlerMethod对象HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally {this.mappingRegistry.releaseReadLock(); }}/** * 通过lookupPath解析最终的handler * 源码位置:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(String, HttpServletRequest) */protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List matches = new ArrayList<>(); // 根据uri从mappingRegistry.pathLookup获取 RequestMappingInfo // pathLookup会在初始化阶段解析好 List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath); if (directPathMatches != null) {// 如果根据path能直接匹配的RequestMappingInfo 则用该mapping进行匹配其他条件(method、header等)addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) {// 如果无path匹配,用所有的RequestMappingInfo通过AntPathMatcher匹配addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request); } if (!matches.isEmpty()) {// 选择第一个为最匹配的Match bestMatch = matches.get(0); /*** 如果匹配到多个@RequestMapping(value="https://www.it610.com/mappin?")@RequestMapping(value="https://www.it610.com/mappin*")@RequestMapping(value="https://www.it610.com/{xxxx}")@RequestMapping(value="https://www.it610.com/**")*/if (matches.size() > 1) {//创建MatchComparator的匹配器对象Comparator comparator = new MatchComparator(getMappingComparator(request)); /** 根据精准度排序大概是这样的: ? > * > {} >**具体可以去看:* @see org.springframework.util.AntPathMatcher.AntPatternComparator#compare(java.lang.String, java.lang.String)*/matches.sort(comparator); // 排完序后拿到优先级最高的bestMatch = matches.get(0); if (logger.isTraceEnabled()) {logger.trace(matches.size() + " matching mappings: " + matches); }// 是否配置CORS并且匹配if (CorsUtils.isPreFlightRequest(request)) {for (Match match : matches) {if (match.hasCorsConfig()) {return PREFLIGHT_AMBIGUOUS_MATCH; }}}else {//获取第二最匹配的Match secondBestMatch = matches.get(1); //若第一个和第二个是一样的 抛出异常if (comparator.compare(bestMatch, secondBestMatch) == 0) {Method m1 = bestMatch.getHandlerMethod().getMethod(); Method m2 = secondBestMatch.getHandlerMethod().getMethod(); String uri = request.getRequestURI(); throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}"); }}}//把最匹配的设置到request中request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod()); handleMatch(bestMatch.mapping, lookupPath, request); //返回最匹配的return bestMatch.getHandlerMethod(); } else { // return nullreturn handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request); }}

到此这篇关于java spring mvc处理器映射器介绍的文章就介绍到这了,更多相关spring mvc处理器映射器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    推荐阅读