1、前置
1、这里是两个异常(别名as)
第一个异常 ‘as’ A: A bean with that name has already been defined and overriding is disabled.
第二个 ‘as’ B: Method GetFeignClient#getParameters(String,String) not annotated with HTTP method type (ex. GET, POST)
2、看了一下网上给的解决方案, 但是并没有详细的说明, 本篇文章会进行详细的解释
3、版本: Spring Cloud: Hoxton.SR3、spring-cloud-openfeign: 2.2.2.RELEASE
2、重现异常A:
@FeignClient(name = "provider")
public interface GetFeignClient {
@RequestMapping(value = "/getNoParameters", method = RequestMethod.GET)
CommonResult getNoParameters();
}
@FeignClient(name = "provider")
public interface PostFeignClient {
@RequestMapping(value = "/testPost/postNoParameters", method = RequestMethod.POST)
CommonResult postNoParameters();
}
启动项目报错: The bean ‘provider.FeignClientSpecification’ could not be registered. A bean with that name has already been defined and overriding is disabled.
3、重现异常B:
在重现异常B之前, 我们要先将异常A给解决掉, 就用最快捷的方式进行解决:(强烈不推荐该方式, 后面会说)
spring:
main:
allow-bean-definition-overriding: true
@FeignClient(name = "provider")
public interface GetFeignClient {
@RequestMapping(value = "/getNoParameters", method = RequestMethod.GET)
CommonResult getNoParameters();
}
@FeignClient(name = "provider", configuration = FooConfiguration.class)
public interface HeaderFeignClient {
@RequestLine("GET /testHeard/getHeard")
CommonResult getHeard(@SpringQueryMap TestEntity data, @HeaderMap Map<String, Object> headerMap);
}
FooConfiguration:
package com.chaim.feignserver.config;
import feign.Contract;
import org.springframework.context.annotation.Bean;
/**
* 详情说明见 Readme.md
* 可以参考代码地址
*
* @author Chaim
* @date 2021/4/19 10:59
*/
//@Configurable
public class FooConfiguration {
/**
* 将契约改为 feign 原生的默认契约.
* 可以使用feign自带的注解
*
* @return
*/
@Bean
public Contract feignContract() {
return new feign.Contract.Default();
}
关于FooConfiguration 说明:
@Configurable
feign 配置
在 SpringCloud 中,Feign 的默认配置类是 FeignClientsConfiguration, 该类定义了 feign 默认使用的编码器、解码器、所使用的契约等.
SpringCloud允许通过注解@FeignClient的configuration属性自定义Feign的配置 (@FeignClient(configuration= FooConfiguration.class)),
自定义配置的优先级比FeighClientsConfiguration要高.
可以使用 @Configurable, 声明这是一个配置类, 但此时不能将该放置在主应用程序上下文 @ComponentScan 所扫描的包中, 否则该配置将会被所有Feign Client共享,无法实现细粒度配置!
反之, 也可以不使用 @Configurable, 从而避免父子上下文问题
官网中有介绍(1.2): https://docs.spring.io/spring-cloud-openfeign/docs/2.2.x-SNAPSHOT/reference/html/index.html
摘抄:
FooConfiguration does not need to be annotated with @Configuration. However, if it is, then take care to exclude it from any @ComponentScan that would otherwise include this configuration as it will become the default source for feign.Decoder, feign.Encoder, feign.Contract, etc., when specified. This can be avoided by putting it in a separate, non-overlapping package from any @ComponentScan or @SpringBootApplication, or it can be explicitly excluded in @ComponentScan.
启动项目报错: FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Method GetFeignClient#getParameters(String,String) not annotated with HTTP method type (ex. GET, POST)
4、分析问题
异常A: bean名称相同, 重复的bean被定义了, 这个就不多说了
异常B: 这个就有点意思了, 他也是基于bean名称重复定义导致产生的, 简单的深入一下
1、HeaderFeignClient 指定了原生契约, 他的bean名字是provider,
2、GetFeignClient 未指定原生契约, 他的bean名字也是provider,
3、而@RequestMapping并不属于原生契约, 也就是说原生契约下不支持该注解, 就会报该error
4、那么当spring注入名称:provider引用原生契约对应的注解, 该provider都只能使用原生契约支持的注解
测试一下我们的说法:
@FeignClient(name = "provider", configuration = FooConfiguration.class)
public interface HeaderFeignClient extends HeaderService {
@RequestLine("GET /testHeard/getHeard")
CommonResult getHeard(@SpringQueryMap TestEntity data, @HeaderMap Map<String, Object> headerMap);
@RequestMapping(value = "/getNoParameters", method = RequestMethod.GET)
CommonResult getNoParameters();
}
启动项目依旧报错, 那么就验证了我们上面说的流程
5、解决方法
1、指定: contextId: 用作bean名,但不会作为服务id
@FeignClient(name = "provider", contextId = "headerProvider", configuration = FooConfiguration.class)
public interface HeaderFeignClient {
@RequestLine("GET /testHeard/getHeard")
CommonResult getHeard(@SpringQueryMap TestEntity data, @HeaderMap Map<String, Object> headerMap);
}
2、开启了原生契约支持, 那么就只能使用原生契约支持的注解, 不能混用
3、不到万不得已的情况下 不要用spring.main.allow-bean-definition-overriding=true用我们话说就是捏到鼻子哄眼睛
6、完结
1、简单说该问题, 如果使用@RequestLine等原生契约支持的注解, 那么就要通过configuration 配置原生契约, 并且只能使用原生契约支持的注解
2、openfeign对应的其余文章:
代码地址以及对应的postman文件
Feign的使用示列–呕心沥血之作(1)
Feign的@FeignClient详解–呕心沥血之作(2)
Feign的默认契约注解详解–呕心沥血之作(3)
Feign异常–Request method ‘POST‘ not supported
Feign异常–A bean with that name | HTTP method type (ex. GET, POST)