文章目錄
- 1、前置
- 2、重制異常A:
- 3、重制異常B:
- 4、分析問題
- 5、解決方法
- 6、完結
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 配置原生契約, 并且隻能使用原生契約支援的注解