SpringMVC-Ambiguous mapping 问题实践

思君令人老,努力加餐饭

1 前言

今天在项目开发中遇到了一个 Ambiguous mapping 问题,错误信息展示为 Ambiguous mapping. Cannot map 'xxxController' method 。起因是项目(项目是微服务架构,需要引入其他项目的 api)开发中使用了其它项目的 api jar 包,在控制器层声明的 RequestMapping 和 jar 包中的 RequestMapping 一致造成的,项目启动时,会扫描所有的包并创建 RequestMappingHandler ,在 doCreateBeaninitializeBean 阶段发生异常。

2 问题分析

遇到的报错信息如下图所示,当看到这样的信息时,真是一头雾水。原因就是在 MemberOrderController 中的方法和引入 jar 包中的 MemberOrderApi 中的方法使用的路径是一样的。那么在两者路径都不变动的情况下,怎么去修改这个问题呢?

这里需要介绍一下 RequestMappingInfo, 可以从下图看到在控制器层写的每一个 Mapping 都可以在 RequestMappingInfo 中找到对应的属性,其包含了所有的映射信息。

异常出现在 Spring 的 refresh 阶段,RequestMappingHandlerMapping 实现了 Bean 初始化的接口 InitializingBean,在 bean 加载完成后会自动调用 afterPropertiesSet 方法进行后置处理,在此方法中调用了 initHandlerMethods,异常的触发是在以下链路中。

复制代码
RequestMappingHandlerMapping.registerHandlerMethod
AbstractHandlerMethodMapping.registerHandlerMethod
AbstractHandlerMethodMapping.validateMethodMapping

在调用 validateMethodMapping是传进来的 mapping 的类型即 RequestMappingInfo, 会从 mappingLookup 中查找对应的 HandlerMethod 来判断是否存在。

通过上面的分析,我们知道要想解决这样的报错,在请求路径不变的情况下,能修改的只有 RequestMappingInfo 中的属性,包括请求头,参数,名称、consumesproduces 等。任意修改一项即可实现项目中存在同样的请求路径,不过在客户端发起请求时,需要严格按照 mapping 的参数要求来请求,才能执行对应的方法。这里最常用的就是同一个请求路径,采用不同的方法(postget )也可以实现。

3 RequestMappingHandlerMapping

在上述问题分析中,我们知道了 RequestMappingHandlerMapping 在处理 Controller 中的重要性,在本节中将分享如何利用其在项目启动时打印应用的所有接口。在项目中创建配置文件 AppHandlerMapping 实现集成,重写 registerHandlerMethod 方法即可获取到对应的 requestmapping 信息。通过以上的操作,既可以打印项目中所有的接口信息。

除了打印项目接口列表外,还可以通过自定义 RestMapping 来处理请求,主要是为了了解 RequestMappingHandlerMapping 的作用,方便深入理解其原理和逻辑思想,可以更好的解决实际开发过程中遇到的问题,在遇到棘手的问题时,可以利用其特点找到巧妙的解决方案。

如下图所示,通过重写 getMappingForMethod 方法,可以实现自定义注解的解析,通过获取其特定的属性,重新构建 RequestMappingInfo 对象,即可实现特定接口的注册和功能实现。这在实际的开发中使用比较少,但是可以作为一项技术储备来学习。在实际开发过程中,可以根据需要对 SpringMvc 的功能点进行拓展,实现特定的业务需求。这里需要注意的是 AnnotatedElementUtils.findMergedAnnotation,这是一个很好用的工具类,可以通过它找到方法上的注解。

4 总结

在本文主要分享了 SpringMVC-Ambiguous mapping 的问题解决方法,以及出现该问题的原因。由此引出了 RequestMappingHandlerMapping,通过其简单实现了项目接口的打印和自定义注解解析。本文中所涉及的代码已经上传至 github, 欢迎交流学习。项目地址 springboot-auth

相关推荐
A尘埃4 小时前
Spring Event 企业级应用
java·spring·event
一叶飘零_sweeeet9 小时前
SPI 机制深度剖析:Java、Spring、Dubbo 的服务发现哲学与实战指南
java·spring·dubbo
练习时长一年10 小时前
logback-spring.xml 文件
xml·spring·logback
abigalexy13 小时前
深入图解Spring Cloud底层设计
spring·spring cloud
越来越无动于衷17 小时前
代理模式深度解析:从静态代理到 Spring AOP 实现
java·spring·代理模式
喂完待续17 小时前
【序列晋升】12 Spring Boot 约定优于配置
java·spring boot·spring·架构·约定大于配置·序列晋升·tech arch
ankleless21 小时前
Spring 框架深度解析:从核心原理到实战应用
java·spring
带刺的坐椅21 小时前
Spring AOP 与 Solon AOP 有什么区别?
java·spring·solon·aop
PythonicCC2 天前
Django中的MVC和MVT模式
数据库·django·mvc
寒士obj2 天前
Spring容器Bean的创建流程
java·后端·spring