Feign报错 'xx.FeignClientSpecification'を登録できませんでした。オーバーライドは無効です

1.エラーの説明

    最近、SpringBoot 2.2.11.RELEASEを使用してFeign開発と連携すると、次のエラーが発生しました。

org.springframework.beans.factory.support.BeanDefinitionOverrideException: 
Invalid bean definition with name 'XXX.FeignClientSpecification' defined in null: 
Cannot register bean definition [Generic bean: class [org.springframework.cloud.openfeign.FeignClientSpecification];  bound.

Description:

The bean 'XXX.FeignClientSpecification' could not be registered. 
A bean with that name has already been defined and overriding is disabled.

2.問題の原因

エラーの説明によると、Bean'XXX.FeignClientSpecification 'を登録できませんでした。その名前のBeanはすでに定義されており、オーバーライドは無効になっています。以下に示すように、プロジェクトで2つのFeignクライアントが定義されています。

@FeignClient(value = "XXXX")
public interface ApiService1 {
    @GetMapping("/user/{username}")
    UserDto query(@PathVariable("username") String username);
}
@FeignClient(value = "XXX")
public interface MenuApiService {

    @GetMapping("/allMenus")
    List<MenuDto> queryAll();

}

2つのFeignクライアントで構成された値が同じであるため、起動時に上記のエラーが報告されます。

三、解決策

アノテーション@FeignClientにcontextId 属性追加し、  異なる値を割り当てます。それは解決することができます。

4、分析

スタートアップクラスに追加された@EnableFeignClientsアノテーションを見てみましょう。  これにより、以下に示すようにFeignClientsRegistrarクラスが導入  されます。

 

次にFeignClientsRegistrarクラスのソースコードを分析し ています

 1.継承階層

このクラスは、Beanを動的に登録するために使用されるImportBeanDefinitionRegistrarインターフェースを実装していることが わかります。インターフェイス情報は次のとおりです。

public interface ImportBeanDefinitionRegistrar {
	
	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}


	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}

}

2. FeignClientsRegistrarで実装クラス

FeignClientsRegistrarのクラスが実装 registerBeanDefinitionsの方法ImportBeanDefinitionRegistrarのインターフェースを  、次のように:

次にregisterFeignClientsメソッドの実装に焦点を当て ましょう。このメソッドのロジックは非常に単純で、主に @EnableFeignClientsアノテーションで設定されたclients属性とbasePackages属性です。プロジェクトで@FeignClient  アノテーションで構成されたすべてのクラスまたはインターフェイスをスキャンします。メソッド分析は、具体的にはFeignClientクライアントにすることができます。このメソッドのメインコードを次のように見てください(他のソースコードを確認できます)。

メインコードは次のとおりです。

1. getClientName(attributes)メソッドを呼び出して、メイン名を取得します。ソースコードは次のとおりです。

	private String getClientName(Map<String, Object> client) {
		if (client == null) {
			return null;
		}
		String value = (String) client.get("contextId");
		if (!StringUtils.hasText(value)) {
			value = (String) client.get("value");
		}
		if (!StringUtils.hasText(value)) {
			value = (String) client.get("name");
		}
		if (!StringUtils.hasText(value)) {
			value = (String) client.get("serviceId");
		}
		if (StringUtils.hasText(value)) {
			return value;
		}

		throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
				+ FeignClient.class.getSimpleName());
	}

このメソッドのコードロジックは非常に単純です。contenxtIdを取得します。存在しない場合は値を取得し、値が存在しない場合は名前を取得して順番に取得します。

 2.コール  registerClientConfigurationを次のように豆、ソースコードを登録する方法です。

	private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
			Object configuration) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientSpecification.class);
		builder.addConstructorArgValue(name);
		builder.addConstructorArgValue(configuration);

       // 关键点:根据 getClientName 方法获取的值 注册 Bean 。
		registry.registerBeanDefinition(
				name + "." + FeignClientSpecification.class.getSimpleName(),
				builder.getBeanDefinition());
	}

ではgetClientName()、ソースコード、名前がcontenxtId、名前、値、(期限切れマーク)@FeignClient注釈でいるServiceIDであることがわかります。beanName:name + "." + FeignClientSpecification.class.getSimpleName()したがって、同じ名前のFeigClientアノテーションを使用すると、同じBean名がIocに挿入されます。したがって、エラーはFeignClientSpecificationクラスが原因で発生します。

おすすめ

転載: blog.csdn.net/small_love/article/details/111604118