96SEO 2026-02-20 05:09 0
rl是如何与对应Handler的即Controller对应method映射的

在上篇中提到在SpringMVC中初始化9大内置组件的时候其中有一个组件就是HandlerMapping在初始化HandlerMapping的时候会加载代码中所有标注了Controller和RequestMapping的类到spring容器中作为一个个bean对象。
关键类RequestMappingHandlerMapping
类图上看出RequestMappingInfoHandlerMapping继承了AbstractHandlerMethodMapping。
实现了InitializingBean接口并且实现了afterPropertiesSet方法。
所以在spring初始化这个RequestMappingHandlerMapping对象的时候会进入到afterPropertiesSet()中这个里面会调用父类AbstractHandlerMethodMapping的afterPropertiesSet()然后调用initHandlerMethods()。
在其中会初始化所有的HandlerMethods。
扫描所有的Handler类获取所有带有Controller或RequestMapping注解的类。
遍历每个Handler类获取类中的所有方法。
对于每个方法判断是否存在RequestMapping注解。
如果存在RequestMapping注解则解析该注解获取其中的属性值如请求路径、请求方法、请求参数等。
根据解析到的属性值生成一个RequestMappingInfo对象该对象代表了一个请求路径和请求方法的映射关系。
将生成的RequestMappingInfo对象与对应的HandlerMethod对象进行关联形成一个映射关系将该映射关系保存到RequestMappingInfoHandlerMapping中的pathLookup和registry两个Map中。
pathLookup是一个Map以请求路径作为键将对应的RequestMappingInfo对象作为值存储起来用于后续处理请求时的查找。
registry是一个Map以RequestMappingInfo对象作为键将对应的HandlerMethod对象作为值存储起来用于后续执行相应的方法。
遍历完所有的Handler类和方法后初始化完成此时已经将请求路径、请求方法和对应的HandlerMethod对象都保存起来了。
当有实际的请求进来时RequestMappingHandlerMapping会根据请求的路径和方法从pathLookup中查找对应的RequestMappingInfo对象。
然后通过RequestMappingInfo对象从registry中获取对应的HandlerMethod对象从而执行相应的方法。
HandlerMethod对象是在处理请求时动态生成的它包含了方法的相关信息如所属的类、方法名、参数列表等。
{if(this.logger.isDebugEnabled())
this.getApplicationContext());}//这里是获取应用中所有Object的bean的名字String[]
this.detectHandlerMethodsInAncestorContexts?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.obtainApplicationContext(),
Object.class):this.obtainApplicationContext().getBeanNamesForType(Object.class);String[]
beanNames.length;//遍历这个含有应用中所有beanName的字符串数组并得到这个beanName对应的bean的类型for(int
var2[var4];if(!beanName.startsWith(scopedTarget.))
{//根据这个beanName对应的beanType的类型beanType
this.obtainApplicationContext().getType(beanName);}
{if(this.logger.isDebugEnabled())
var8);}}//判断这个根据这个bean的类型判断是不是一个handlerif(beanType
{this.detectHandlerMethods(beanName);}}}this.handlerMethodsInitialized(this.getHandlerMethods());}1.1
这个Bean是否含有Controller注解或RequestMapping注解如果是就表示是一个handler
(AnnotatedElementUtils.hasAnnotation(beanType,
||AnnotatedElementUtils.hasAnnotation(beanType,
获取这个handler中所有requestMappinng的方法然后循环去注册该方法与对应requestMapping信息到一个名为registry的一个HashMap中去
String?this.obtainApplicationContext().getType((String)handler):handler.getClass();if(handlerType
ClassUtils.getUserClass(handlerType);//获取这个handler中有requestMapping的方法//这个methods的Map结构为key是一个Method对象value是一个RequestMappingInfo对象Map
MethodIntrospector.selectMethods(userType,
this.getMappingForMethod(method,
var4);}});if(this.logger.isDebugEnabled())
{this.logger.debug(methods.size()
methods);}//循环去注册Method与RequestMappingInfo的关系methods.forEach((method,
AopUtils.selectInvocableMethod(method,
userType);this.registerHandlerMethod(handler,
1、若这个targetType不是一个代理类就获得它本身的类以及它的接口放入handlerTypes这么一个Set中去。
2、遍历这个handlerTypes,找到用户自己定义的方法并过滤出有requestMapping的方法并将之塞入一个methodMap中
MethodIntrospector.MetadataLookupT
null;//若这个targetType不是一个代理类就获得它本身的类以及它的接口if(!Proxy.isProxyClass(targetType))
ClassUtils.getUserClass(targetType);handlerTypes.add(specificHandlerType);}handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));Iterator
handlerTypes.iterator();//遍历while(var5.hasNext())
null?specificHandlerType:currentHandlerType;//找到用户自己定义的方法并过滤出有requestMapping的方法并将之塞入一个methodMap中ReflectionUtils.doWithMethods(currentHandlerType,
ClassUtils.getMostSpecificMethod(method,
metadataLookup.inspect(specificMethod);if(result
BridgeMethodResolver.findBridgedMethod(specificMethod);if(bridgedMethod
metadataLookup.inspect(bridgedMethod)
ReflectionUtils.USER_DECLARED_METHODS);}return
ReflectUtilsl.doWithMethods(Class?
ReflectionUtils.MethodCallback,
1、首先获取这个Class中所有定义的方法并且将之存入一个methods的Method数组中
2、遍历这个methods数组中的method如果这个mf方法拦截器为空或者这个method与方法拦截器mf的匹配规则对应就回调mc.doWith方法。
这个mc.doWith()就会调用回到去执行doWithMethods()的第二个lamda表达式。
在这个表达式中又会继续回掉执行另一个方法。
其中这个mf方法拦截器就是这个RelectionUtils.USER_DECLARED_METHODS顾名思义就是用户自己定义的方法而非继承与Object类的方法什么的。
执行给定回调操作在给定类和父类(或者给定的接口或父接口)的所有匹配方法*/public
从缓存中获取clazz的所有声明的方法包括它的所有接口中所有默认方法没有时就从{code
对method执行回调操作mc.doWith(method);}catch
java.lang.Object}上声明的所有非桥接非合成方法匹配的预购建方法过滤器或者clazz的父类不为Objectif
子类和父类发生的相同命名方法将出现两次除非被mf排查doWithMethods(clazz.getSuperclass(),
子类和父类发生的相同命名方法将出现两次除非被mf排查doWithMethods(superIfc,
当执行到这个方法时会回掉执行doWithMethods()中的第二个入参即lamda表达式
ClassUtils.getMostSpecificMethod(method,
metadataLookup.inspect(specificMethod);if
BridgeMethodResolver.findBridgedMethod(specificMethod);if
metadataLookup.inspect(bridgedMethod)
metadataLookup.inspect(specificMethod)–
执行到inspect方法的时候又会继续调用MethodIntrospector.selectMethods()方法中的第二个入参数去执行第二个lamda表达式。
MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookupT)
最终执行到getMappingForMethod()找到这个方法上的RequestMapping如果这个方法上的requestMapping信息不为空的话就去照这个handler类上面的requestMapping信息然后将之合并.
createRequestMappingInfo(method);if
createRequestMappingInfo(handlerType);if
RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);}}return
info;}createRequestMappingInfo()
是请求映射信息的封装对象用来确定请求的URL、请求方法、请求参数等信息
createRequestMappingInfo(AnnotatedElement
AnnotatedElementUtils.findMergedAnnotation(element,
RequestMapping.class);RequestCondition?
?getCustomTypeCondition((Class?)
getCustomMethodCondition((Method)
createRequestMappingInfo(requestMapping,
createRequestMappingInfo(RequestMapping
RequestMappingInfo.paths(resolveEmbeddedValuesInPatterns(requestMapping.path())).methods(requestMapping.method()).params(requestMapping.params()).headers(requestMapping.headers()).consumes(requestMapping.consumes()).produces(requestMapping.produces()).mappingName(requestMapping.name());if
{builder.customCondition(customCondition);}return
builder.options(this.config).build();}1.2.2
//循环去注册Method与RequestMappingInfo的关系methods.forEach((method,
AopUtils.selectInvocableMethod(method,
userType);this.registerHandlerMethod(handler,
{this.mappingRegistry.register(mapping,
通过handler与method创建HandlerMethod对象确保requestMapping唯一映射一个method,
最后注册requestMappingInfo与对应handlerMethod的关系。
{this.readWriteLock.writeLock().lock();try
{//创建HandlerMethod对象这个对象包含了handler与method的信息HandlerMethod
AbstractHandlerMethodMapping.this.createHandlerMethod(handler,
method);//确保同一个requestMapping唯一映射一个method//
不能对应对应methodBthis.assertUniqueMethodMapping(handlerMethod,
mapping);if(AbstractHandlerMethodMapping.this.logger.isInfoEnabled())
{//SpringBoot项目或者SpringMVC项目启动的时候控制台上输出的就是这个AbstractHandlerMethodMapping.this.logger.info(Mapped
handlerMethod);}//注册requestMapping与HandlerMethodInfo的关系this.mappingLookup.put(mapping,
this.getDirectUrls(mapping);Iterator
directUrls.iterator();while(name.hasNext())
(String)name.next();this.urlLookup.add(corsConfig,
null;if(AbstractHandlerMethodMapping.this.getNamingStrategy()
AbstractHandlerMethodMapping.this.getNamingStrategy().getName(handlerMethod,
mapping);this.addMappingName(name1,
handlerMethod);}CorsConfiguration
AbstractHandlerMethodMapping.this.initCorsConfiguration(handler,
{this.corsLookup.put(handlerMethod,
corsConfig1);}this.registry.put(mapping,
AbstractHandlerMethodMapping.MappingRegistration(mapping,
{this.readWriteLock.writeLock().unlock();}}
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback