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

相关推荐
廋到被风吹走9 小时前
【Spring】DispatcherServlet解析
java·后端·spring
廋到被风吹走10 小时前
【Spring】PlatformTransactionManager详解
java·spring·wpf
それども11 小时前
Spring Bean 的name可以相同吗
java·后端·spring
qq_124987075312 小时前
基于微信小程序的电子元器件商城(源码+论文+部署+安装)
java·spring boot·spring·微信小程序·小程序·毕业设计
程序员阿鹏14 小时前
责任链模式
java·spring·servlet·tomcat·maven·责任链模式
黄俊懿14 小时前
【深入理解SpringCloud微服务】Seata(AT模式)源码解析——全局事务的回滚
java·后端·spring·spring cloud·微服务·架构·架构师
关于不上作者榜就原神启动那件事15 小时前
Spring Data Redis 中的 opsFor 方法详解
java·redis·spring
码农小卡拉18 小时前
Java多线程:CompletableFuture使用详解(超详细)
java·开发语言·spring boot·python·spring·spring cloud
程序员阿鹏18 小时前
OOM是如何解决的?
java·开发语言·jvm·spring
jiayong2319 小时前
Arthas 完全指南:原理与实战
java·spring·arthas