【问题标题】:Feign with RibbonClient and Consul discovery without Spring Cloud在没有 Spring Cloud 的情况下使用 RibbonClient 和 Consul 发现 Feign
【发布时间】:2023-10-29 04:53:01
【问题描述】:

我试图将 Feign 设置为与 RibbonClient 一起使用,例如 MyService api = Feign.builder().client(RibbonClient.create()).target(MyService.class, "https://myAppProd");,其中 myAppProd 是我可以在 Consul 中看到的应用程序。现在,如果我为 Feign 客户端使用 Spring 注释(@FeignClient("myAppProd")@RequestMapping),一切正常,因为 Spring Cloud 模块会处理一切。

如果我想使用 Feign.builder()@RequestLine,我会收到错误消息: com.netflix.client.ClientException: Load balancer does not have available server for client: myAppProd.

我最初的想法是 Feign 是为与 Eureka 一起工作而构建的,只有 Spring Cloud 与 Consul 集成,但我对此不确定。

那么,有没有办法让 Feign 在没有 Spring Cloud 的情况下与 Consul 一起工作?

提前致谢。

【问题讨论】:

    标签: spring consul netflix-feign spring-cloud-feign netflix-ribbon


    【解决方案1】:

    在我看来,这不是与 consul 的 feign 工作,它的 feign -> ribbon -> consul。

    RibbonClient 需要从其 LoadBalancer 中找到 myAppProd 的 serverList。 如果没有 ServerList,则会出现错误:'没有可供客户端使用的服务器'。

    这个工作已经由 SpringCloudConsul 和 SpringCloudRibbon 项目完成了,当然你可以再写一个适配器,只是一些胶水代码。恕我直言,您可以将此 spring 依赖项导入您的项目,但 以非 spring 方式使用它。演示代码:

    只需要写一个新的feign.ribbon.LBClientFactory,用ConsulServerList(Spring的类)生成LBClient。

    public class ConsulLBFactory implements LBClientFactory {
    
        private ConsulClient client;
        private ConsulDiscoveryProperties properties;
    
        public ConsulLBFactory(ConsulClient client, ConsulDiscoveryProperties consulDiscoveryProperties) {
            this.client = client;
            this.properties = consulDiscoveryProperties;
        }
    
        @Override
        public LBClient create(String clientName) {
            IClientConfig config =
                ClientFactory.getNamedConfig(clientName, DisableAutoRetriesByDefaultClientConfig.class);
    
            ConsulServerList consulServerList = new ConsulServerList(this.client, properties);
            consulServerList.initWithNiwsConfig(config);
    
            ZoneAwareLoadBalancer<ConsulServer> lb = new ZoneAwareLoadBalancer<>(config);
    
            lb.setServersList(consulServerList.getInitialListOfServers());
            lb.setServerListImpl(consulServerList);
            return LBClient.create(lb, config);
        }
    }
    

    然后在feign中使用:

    public class Demo {
        public static void main(String[] args) {
            ConsulLBFactory consulLBFactory = new ConsulLBFactory(
                new ConsulClient(),
                new ConsulDiscoveryProperties(new InetUtils(new InetUtilsProperties()))
            );
    
            RibbonClient ribbonClient = RibbonClient.builder()
                .lbClientFactory(consulLBFactory)
                .build();
    
            GitHub github = Feign.builder()
                .client(ribbonClient)
                .decoder(new GsonDecoder())
                .target(GitHub.class, "https://api.github.com");
    
            List<Contributor> contributors = github.contributors("OpenFeign", "feign");
            for (Contributor contributor : contributors) {
                System.out.println(contributor.login + " (" + contributor.contributions + ")");
            }
        }
    
        interface GitHub {
            @RequestLine("GET /repos/{owner}/{repo}/contributors")
            List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
        }
    
        public static class Contributor {
            String login;
            int contributions;
        }
    }
    

    你可以找到这个demo code here,在运行这个演示之前添加api.github.com到你当地的领事。

    【讨论】:

      最近更新 更多