如何在 Spring Cloud 中禁用 Ribbon 并仅使用 FeignClient

Posted

技术标签:

【中文标题】如何在 Spring Cloud 中禁用 Ribbon 并仅使用 FeignClient【英文标题】:How to Disable Ribbon and just use FeignClient in Spring Cloud 【发布时间】:2018-09-20 02:43:04 【问题描述】:

我知道我们可以通过提供 url Ex 来强制 FeignClient 使用 OkHttp 而不是 Ribbon。 @FeignClient(url="serviceId", name="serviceId")

即使只提供了名称,我也希望使用 OkHttpClient。前任。 @FeignClient(name="serviceId")

根据 Spring Cloud 文档“如果启用了 Ribbon,则它是 LoadBalancerFeignClient,否则使用默认的 feign 客户端。”

如何禁用功能区以便使用默认的 feign 客户端。

【问题讨论】:

ribbon 是一个负载均衡器,我们不使用它的 http 客户端,所以我有点困惑。你可以用丝带 OkHttp。这就是你想要的吗? Netflix FeignClient 默认会寻找负载均衡器。我想在没有负载均衡器的情况下使用 OkHttp。我可以通过在@feignClient 注释中提供 url 和 name 属性来实现这一点。但我想知道是否可以通过在@feignclient 注释中提供 name 属性来实现相同的目标。 只使用名称将始终使用负载均衡器 所以即使功能区不在类路径上,它仍然会寻找负载均衡器。正确的?是否可以通过某种解决方法覆盖该行为? 如果功能区不在类路径上,那么 url 来自哪里? 【参考方案1】:

互联网上的解决方案都不适合我。

    只需在 url 部分设置绝对 url 就会导致负载平衡异常
// this resulted in java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: localhost

@Lazy
@Configuration
@Import(FeignClientsConfiguration.class)
public class MyConfig 

    @LocalServerPort
    private int port;

    @Bean
    public MyClient myClient(final Decoder decoder, final Encoder encoder, final Client client) 
        return Feign.builder().client(client)
            .encoder(encoder)
            .decoder(decoder)
            .target(MyClient.class, "http://localhost:" + localServerPort);
    

    设置spring.cloud.loadbalancing.ribbon.enabled=false 导致应用程序上下文问题。需要禁用其他设置才能使其正常工作。我没有进一步探究
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'eurekaLoadBalancerClientConfiguration': Invocation of init method failed; nested exception is java.lang.NullPointerException

    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
...
...

我的工作解决方案

最后,在查看org.springframework.cloud.openfeign.ribbon.DefaultFeignLoadBalancedConfiguration中的源代码后,我想出了这个解决方案

@Lazy // required for @LocalServerPort to work in a @Configuration/@TestConfiguration
@TestConfiguration
@Import(FeignClientsConfiguration.class)
public class MyConfig 

    @LocalServerPort
    private int port;

    @Bean
    public MyClient myClient(Decoder decoder, Encoder encoder, Client client, Contract contract) 
        return Feign.builder().client(client)
            .encoder(encoder)
            .decoder(decoder)
            .contract(contract)
            .target(MyClient.class, "http://localhost:" + localServerPort);
    

    // provide a default `FeignClient` so that Spring will not automatically create their LoadBalancingFeignClient
    @Bean
    public Client feignClient(SpringClientFactory clientFactory) 
        return new Client.Default(null, null);
    

【讨论】:

【参考方案2】:

它与 Ribbon 无关。

检查一下:

feign:
  httpclient:
    enabled: false

这将禁用 spring cloud 自动配置的 httpclient,并将在上下文中搜索名为 httpClient@Bean。所以在@Configuration 类中提供@Bean 的定义,仅此而已。

在spring cloud feign中查看类FeignAutoConfiguration

https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html

【讨论】:

【参考方案3】:

我有同样的问题,但我的设置有点不同,我没有让它在我的情况下工作(使用带有 spring mvc 样式注释的 spring-cloud-starter-openfeign)。


仅供参考:我需要一个带有 SSLSocketFactory 的自定义客户端,最后只为客户端创建了 bean 并将 URL 保留在 @FeignClient

 @Bean
 public Client myClient() 
     return new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
 

但是,我们确实有使用 spring-cloud-starter-feign 的项目,其中没有在注释上提供 URL。不确定下面的配置是否完整(我没有设置),但它可能会为您指明正确的方向...

依赖项

compile("org.springframework.cloud:spring-cloud-starter-feign") 
    exclude group: 'org.springframework.cloud', module: 'spring-cloud-starter-ribbon'
    exclude group: 'org.springframework.cloud', module: 'spring-cloud-starter-archaius'

配置

@Configuration
@Import(FeignClientsConfiguration.class) // org.springframework.cloud.netflix.feign.FeignClientsConfiguration
public class MyConfig 

    @Value("$client.url")
    private String url;    

    @Bean
    public MyClient myClient(final Decoder decoder, final Encoder encoder, final Client client) 
        return Feign.builder().client(client)
            .encoder(encoder)
            .decoder(decoder)
            .target(MyClient.class, url);
    

【讨论】:

以上是关于如何在 Spring Cloud 中禁用 Ribbon 并仅使用 FeignClient的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Cloud 中禁用 Ribbon 并仅使用 FeignClient

spring-cloud-feign负载均衡组件

在 Spring Cloud AWS 中禁用 Cloudformation

在本地禁用 Spring Cloud Kubernetes

Spring Cloud——什么是微服务?

Spring Cloud(Dalston.SR5)--Zuul 网关-微服务集群