How to Disable Ribbon and just use FeignClient in Spring Cloud

I am aware that we can force FeignClient to use OkHttp instead of Ribbon by providing the url Ex. @FeignClient(url="serviceId", name="serviceId")

I want the OkHttpClient to be used even when just the name is provided. Ex. @FeignClient(name="serviceId")

As per the spring cloud documentation "if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used."

How can I disable ribbon so that the default feign client will be used.

Upvotes: 9

Views: 14930

Answers (3)

Isen Ng
Isen Ng

Reputation: 1466

None of the solutions on the internet worked for me.

  1. Simply setting an absolute url in the url portion resulted in loadbalancing exceptions
// 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);
    }
}
  1. setting spring.cloud.loadbalancing.ribbon.enabled=false resulted in application context problems. Additional settings needs to be disabled for this to work. I did not probe further
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)
...
...

My working solution

Finally, after inspecting the source code in org.springframework.cloud.openfeign.ribbon.DefaultFeignLoadBalancedConfiguration, I came up with this solution

@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);
    }
}

Upvotes: 2

WesternGun
WesternGun

Reputation: 12728

It has nothing to do with Ribbon.

Check this:

feign:
  httpclient:
    enabled: false

This will disable the spring cloud autoconfigured httpclient, and will search a @Bean named httpClient in the context. So provide the definition of @Bean in a @Configuration class and that's all.

Check class FeignAutoConfiguration in spring cloud feign.

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

Upvotes: 0

Clauds
Clauds

Reputation: 950

I had the same question but my setup is a bit different and I did not get it working in my case (using spring-cloud-starter-openfeign with spring mvc style annotations).


FYI: I needed a custom client with an SSLSocketFactory and ended up just creating the bean for the client and keeping the url on @FeignClient

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

However, we do have projects using spring-cloud-starter-feign where the URL is not provided on the annotation. Not sure if the config below is complete (I did not set it up) but it might point you in the right direction...

dependencies

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'
}

config

@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);
    }
}

Upvotes: 0

Related Questions