天天看點

Feign異常--A bean with that name | HTTP method type (ex. GET, POST)

文章目錄

  • ​​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.

Feign異常--A bean with that name | HTTP method type (ex. GET, POST)

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)

Feign異常--A bean with that name | 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 配置原生契約, 并且隻能使用原生契約支援的注解