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

相关推荐
麦兜*10 小时前
MongoDB Atlas 云数据库实战:从零搭建全球多节点集群
java·数据库·spring boot·mongodb·spring·spring cloud
麦兜*10 小时前
MongoDB 在物联网(IoT)中的应用:海量时序数据处理方案
java·数据库·spring boot·物联网·mongodb·spring
青衫客3611 小时前
Spring异步编程- 浅谈 Reactor 核心操作符
java·spring·响应式编程
Cyan_RA914 小时前
SpringMVC @RequestMapping的使用演示和细节 详解
java·开发语言·后端·spring·mvc·ssm·springmvc
wuxuanok1 天前
SpringBoot -原理篇
java·spring boot·spring
若鱼19191 天前
spring-kafka消费异常处理
spring·kafka
送秋三十五1 天前
spring源码分析————ListableBeanFactory
java·后端·spring
一又四分之一.1 天前
spring、springboot、springCloud
spring boot·spring·spring cloud
float_六七1 天前
Spring事务注解@Transactional核心机制详解
java·后端·spring
Java水解1 天前
从 “Hello AI” 到企业级应用:Spring AI 如何重塑 Java 生态的 AI 开发
后端·spring