Search code examples
springspring-bootspring-cloud-netflixnetflix-ribbon

required a bean of type 'org.springframework.cloud.netflix.ribbon.SpringClientFactory' that could not be found


I have this test project which I would like to migrate to more recent version:

@Configuration
public class LoadbalancerConfig extends RibbonLoadBalancerClient  {

  public LoadbalancerConfig(SpringClientFactory clientFactory) {
    super(clientFactory);
  }

}

Full code example: https://github.com/rcbandit111/Generic_SO_POC/blob/master/src/main/java/org/merchant/database/service/sql/LoadbalancerConfig.java

Do you know how I can migrate this code to latest load balancer version?


Solution

  • I think examining the RibbonAutoConfiguration class gives you a good hint of how you should configure things. First remove @Configuration from LoadbalancerConfig, I also renamed LoadbalancerConfig to CustomLoadbalancer to prevent confusion.

    public class CustomLoadbalancer  extends RibbonLoadBalancerClient {
      public CustomLoadbalancer(SpringClientFactory clientFactory) {
        super(clientFactory);
      }
    }
    

    add the following dependency to your gradle com.netflix.ribbon:ribbon:2.7.18

    then add a configuration class like:

    @Configuration
    @ConditionalOnClass({Ribbon.class})
    @AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
    @ConditionalOnProperty(value = "spring.cloud.loadbalancer.ribbon.enabled",
        havingValue = "true", matchIfMissing = true)
    @AutoConfigureBefore(LoadBalancerAutoConfiguration.class)
    public class LoadBalancerClientConfig {
      @Autowired(required = false)
      private List<RibbonClientSpecification> configurations = new ArrayList<>();
    
      @Bean
      public CustomLoadbalancer customLoadbalancer() {
        return new CustomLoadbalancer(springClientFactory());
      }
    
      @Bean
      public SpringClientFactory springClientFactory() {
        SpringClientFactory factory = new SpringClientFactory();
        factory.setConfigurations(this.configurations);
        return factory;
      }
    
    }
    

    If you want to use Spring cloud load balancer instead of above configuration add spring-cloud-starter-loadbalancer dependency to your gradle.build and for configuration you only need this bean:

      @LoadBalanced
      @Bean
      RestTemplate getRestTemplate() {
        return new RestTemplate();
      }
    

    This RestTemplate pretty works identical to standard RestTemplate class, except instead of using physical location of the service, you need to build the URL using Eureka service ID.

    Here is an example of how could you possibly use it in your code

     @Component
    public class LoadBalancedTemplateClient {
      
      @Autowired
      RestTemplate restTemplate;
      @Autowired
      User user;
    
      public ResponseEntity<Result> getResult() {
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder
            .fromHttpUrl("http://application-id/v1/") // application id registered in eureka
            .queryParam("id", user.getUserId());
        return restTemplate.getForEntity(uriComponentsBuilder.toUriString(),
            Result.class);
      }
    }
    

    Also if you wish to use reactive client the process is the same first define the bean:

    @LoadBalanced
    @Bean
    WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
    

    and then inject and use it when you need:

      @Autowired
      private WebClient.Builder webClient;
    
      public Mono<String> doSomething() {
        return webClient
            .build()
            .get()
            .uri("http://application-id/v1/")
            .retrieve()
            .bodyToMono(String.class);
      }
    

    Also you can check documentation for additional information: documentation