feign Ambiguous mapping 解决方式
程序员文章站
2022-07-15 12:28:56
...
Feign Ambiguous mapping 解决方式
背景
feign在使用过程中,一般先定义接口,再定义具体实现的controller,如下所示
@FeignClient(name = "shore-app")
public interface StoreApi {
@GetMapping("/api/store/getStoreNum")
Integer getStoreNum();
@GetMapping("/api/store/getStoreNumByCondition1")
Integer getStoreNumByCondition1();
@GetMapping("/api/store/getStoreNumByCondition2")
Integer getStoreNumByCondition2();
}
实现定义
@RestController
public class StoreController implements StoreApi {
@Override
public Integer getStoreNum() {
return Integer.MAX_VALUE;
}
@Override
public Integer getStoreNumByCondition1() {
return Integer.MAX_VALUE;
}
@Override
public Integer getStoreNumByCondition2() {
return Integer.MAX_VALUE;
}
}
这种方式去提供Feign给其他模块调用也是比较简洁的,不过在定义controller
很多人做法是把url公共的部分抽取出来,如下
@FeignClient(name = "shore-app")
@RequestMapping("/api/store")
public interface StoreApi {
@GetMapping("/getStoreNum")
Integer getStoreNum();
@GetMapping("/getStoreNumByCondition1")
Integer getStoreNumByCondition1();
@GetMapping("/getStoreNumByCondition2")
Integer getStoreNumByCondition2();
}
然后会发现项目启动报错,有相同的url路径,启动不起来,报错如下
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'org.github.hoorf.store.api.StoreApi' method
org.github.hoorf.store.api.StoreApi#getStoreNumByCondition2()
to {GET /api/store/getStoreNumByCondition2}: There is already 'storeController' bean method
org.github.hoorf.store.controller.StoreController#getStoreNumByCondition2() mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
报错原因是@RequestMapping
标注上,被spring识别为controller
本文介绍的是一种新的feign定义模式去解决这问题,既能保持原有的controller
使用习惯,又能将feign定义的接口复用到其他项目
实现
工程目录分包依赖情况
e1
|--e1-api
| |--e1-store-api
| |--e1-account-api
| |--e1-common
|--e1-acount
|--e1-store
其中e1-account
,e1-store
分别依赖e1-api
,e1-api
为所有api的聚合依赖
- 自定义Feign注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@FeignClient
@Conditional(AdaptiveFeignCondition.class)
public @interface AdaptiveFeign {
@AliasFor(annotation = FeignClient.class)
String value() default "";
@AliasFor(annotation = FeignClient.class)
Class<?> fallback() default void.class;
@AliasFor(annotation = FeignClient.class)
Class<?> fallbackFactory() default void.class;
}
- 定义注解启用条件
基本逻辑就是,如果识别到实现类有controller则不启用Feign注解,识别不到则启用Feign注解
@Slf4j
public class AdaptiveFeignCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ClassMetadata classMetadata = (ClassMetadata) metadata;
String className = classMetadata.getClassName();
Class interfaceClass = null;
try {
interfaceClass = Class.forName(className);
} catch (ClassNotFoundException e) {
}
Set<Class<?>> classSet = ReflectionUtils.getSubTypesOf(interfaceClass);
for (Class<?> implClass : classSet) {
Controller annotation = AnnotationUtils.findAnnotation(implClass, Controller.class);
if (null != annotation) {
// log.debug("{} exits Controller.class ,no init feign {}", implClass.getName(), interfaceClass.getName());
return ConditionOutcome.noMatch(new StringBuffer(implClass.getName()).append(" exits implement").toString());
}
}
return ConditionOutcome.match();
}
}
效果
在 account
模块中使用
@Autowired
private AccountApi accountApi;
注入的是Spring中的AccountApi
具体实现,也就是controller,走的是内部调用
在 store
模块中使用
注入的是AccountApi
Feign的实现,走的是远程调用
具体工程代码https://github.com/hoorf/arch/tree/master/arch-example-1
推荐阅读
-
feign api Ambiguous mapping
-
Ambiguous mapping Cannot map ‘ XXController‘ method,已解决
-
Caused by: java.lang.IllegalStateException: Ambiguous mapping found.解决
-
feign Ambiguous mapping 解决方式
-
Ambiguous mapping found. Cannot map 'XXXController' bean method”解决方法
-
解决“Ambiguous mapping. Cannot map ‘indexController‘ method”报错,其实很简单,只是不够细心
-
springCloud微服务之间通过feign调用方式上传文件找不到文件解决方案
-
springCloud微服务之间通过feign调用方式上传文件找不到文件解决方案
-
Java Ambiguous mapping. Cannot map ‘xxx‘ method问题解决
-
mapstruct 类使用继承时产生Ambiguous mapping methods found for mapping collection element to错误解决