SpringCloud微服务项目解决OpenFeign 注解导致url冲突

微服务
2025-01-13 03:56:40
分享

SpringCloud微服务项目解决@OpenFeign @RequestMapping 注解导致url冲突

问题关键词: Ambiguous mapping. Cannot map OpenFeign @RequestMapping ==@FeignClient==

URL冲突问题的现象

我们在开发微服时候,api层作为OpenFeign的二方接口SDK,服务的实现 OpenFeign定义的接口实现在Controller上。这种模式开始没毛病,实则问题挺棘手的,因为@RequestMapping注解会继承到Controller,OpenFeign接口上的@RequestMapping注解也会被接口地址注册器扫描到,从而导致URL地址冲突。

具体的代码开发如下:

FeignClient类,用于提供给司内二方调用的内部接口

@FeignClient(name = &ampquot;backstage-server&ampquot;,contextId = &ampquot;sysUserApi&ampquot;)
@RequestMapping(&ampquot;/inner/sysUser-api&ampquot;)
public interface SysUserClient {

 &ampnbsp; &ampnbsp;@GetMapping(&ampquot;/sysUser/check&ampquot;)
 &ampnbsp; &ampnbsp;Resp<boolean>checkUser(@RequestParam(&ampquot;staffId&ampquot;) Long staffId);
}

SysUserController 实现SysUserClient的API的控制器

@RestController
public class SysUserController implements SysUserClient {
 &ampnbsp; &ampnbsp;
 &ampnbsp; &ampnbsp;Resp<boolean>checkUser(@RequestParam(&ampquot;staffId&ampquot;) Long staffId){
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;return xxxx;
 &ampnbsp; &ampnbsp;}
}

运行后出现异常

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map &#39;com.xxxx.tech.backstage.controller.SysUserController&#39; method 
com.xxxx.tech.backstage.feign.BackstageSysUserApi#getSysUserList(List)
to {POST /inner/sysUser-api/sysUser/get/list}: There is already &#39;com.xxxx.platform.user.goods.server.client.SysUserClient&#39; bean method
com.xxxx.platform.user.goods.server.client.SysUserClient#getSysUserList(List) mapped.
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:636)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:603)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:318)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:378)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:75)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lambda$detectHandlerMethods$1(AbstractHandlerMethodMapping.java:288)
    at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:286)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(AbstractHandlerMethodMapping.java:258)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:217)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:205)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:189)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1858)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1795)
    ... 51 common frames omitted

解决Springboot项目URL冲突方法

问题原因前面已经分析了,那么现在要解决该问题只需要在注册URL过程将重复扫描的URL排除在外即可。

这里会使用到WebMvcRegistrations接口扩展注册WebURL能力。

需要排除的URL注册的主要特征为: 1、是java定义的interface ; 2、带有@FeignClient注解并加了@RequestMapping注解;

新建类 WebMvcFeignClientExcludeRegistrations 排除在接口上带有FeignClient注解的URL注册

package com.xxx.tech.common.feign.config;

import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * 排除不需要的mapping,例如feignclient注解的mapping
 *<p>* 自动配置@FeignClient 注解的 接口地址扫描。
 * 解决问题:@FeignClient的接口,在Controller实现api接口 @RequestMapping会继承到controller类上,造成路径冲突。
 *
 * @author marker
 */
public class WebMvcFeignClientExcludeRegistrations implements WebMvcRegistrations {


 &ampnbsp; &ampnbsp;@Override
 &ampnbsp; &ampnbsp;public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;return new FeignRequestMappingHandlerMapping();
 &ampnbsp; &ampnbsp;}


 &ampnbsp; &ampnbsp;private static class FeignRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;@Override
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;protected boolean isHandler(Class<?> beanType) {
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;// 如果是接口且有openfeign注解的视为无效扫描
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;if (beanType.isInterface() &ampamp;&ampamp; AnnotatedElementUtils.hasAnnotation(beanType, FeignClient.class)) {
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;return false;
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;}
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;return super.isHandler(beanType);
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;}
 &ampnbsp; &ampnbsp;}

}

加入到装配bean中

 &ampnbsp; &ampnbsp;/**
 &ampnbsp; &ampnbsp; * 自动配置@FeignClient 注解的 接口地址扫描。
 &ampnbsp; &ampnbsp; * 解决问题:@FeignClient的接口,在Controller实现api接口 @RequestMapping会继承到controller类上,造成路径冲突。
 &ampnbsp; &ampnbsp; * @return
 &ampnbsp; &ampnbsp; */
 &ampnbsp; &ampnbsp;@Bean
 &ampnbsp; &ampnbsp;@ConditionalOnMissingBean
 &ampnbsp; &ampnbsp;public WebMvcFeignClientExcludeRegistrations webMvcFeignClientExcludeRegistrations(){
 &ampnbsp; &ampnbsp; &ampnbsp; &ampnbsp;return new WebMvcFeignClientExcludeRegistrations();
 &ampnbsp; &ampnbsp;}

调试以上代码,所有的URL接口地址扫描都会经过FeignRequestMappingHandlerMapping 判断接口注解是否符合标准

调试排查FeignClient的Mapping

</?>

The End
免责声明:本文系转载,版权归原作者所有;旨在传递信息,不代表本站观点和立场。