@FeignClientアノテーションには、以下の主要な属性があります。
これらのクライアントを定義すると、同じname属性を持つため、アプリケーション起動時に以下のエラーが発生します。
このエラーを解決するには、2つの方法があります。
1. nameの重複を避け、contextIdに値を設定する。
2. nameが重複する場合でもBeanDefinitionの上書きを許可するために、spring.main.allow-bean-definition-overriding=trueを設定する。
2番目の方法を使用し、かつ特定のクライアントにカスタム設定を適用したい場合、設定が反映されない問題が発生することがあります。
BeanDefinitionの上書きが許可されている場合、対応するFeignContextの設定も上書きされてしまうため、この問題が発生します。この問題を解決するには、contextIdを個別に設定して、設定が正しく適用されるようにする必要があります。
この動作の背景には、FeignClientsRegistrarがFeignClientの名前に基づいて設定Beanを生成するロジックがあります。名前が同じ場合、後から定義されたものが前のものを上書きしてしまいます。
その後、FeignClientが呼び出されると、FeignClientFactoryBeanのgetTargetメソッドがFeignContextを取得してFeign.Builderを構築します。
FeignClientSpecificationが上書きされた結果、指定したカスタム設定が適用されなくなるのです。
- name: FeignClientの名前を指定します。Ribbonを使用している場合、この名前はサービスディスカバリに使用されるマイクロサービスの名前となります。
- configuration: Feignのカスタム設定クラスを指定します。Encoder、Decoder、ログレベル、Contractなどをカスタマイズできます。
- contextId: FeignClientインスタンスを区別するために使用されます。
public interface CustomerClient1 {
// ... インターフェースメソッド
}
@FeignClient(name = "hbs-service", fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient1 {
// ... インターフェースメソッド
}
public interface CustomerClient2 {
// ... インターフェースメソッド
}
@FeignClient(name = "hbs-service", fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient2 {
// ... インターフェースメソッド
}
Description:
The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
@FeignClient(name = "hbs-service", configuration = FeignSupportConfig.class, fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient2 {
// ... インターフェースメソッド
}
@FeignClient(contextId = "CustomerClient2", name = "hbs-service", configuration = FeignSupportConfig1.class, fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient2 {
// ... インターフェースメソッド
}
// FeignClientsRegistrar.java
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object clientName, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(clientName);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(
clientName + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
// FeignClientFactoryBean.java
public <T> T getTarget() {
FeignContext context = (this.beanFactory != null)
? this.beanFactory.getBean(FeignContext.class)
: this.applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
// ... その他の設定とビルダーの構築
return (T) loadBalancedTarget(builder, context, this.target);
}