通過ribbon 根據服務名獲取所有服務實例的IP和端口列表


代碼使用SpringCloud版本E3

 

業務場景:

今天遇到一個業務場景,要求根據服務名獲取當前微服務集群中所有的對應服務實例的IP和端口,通過分析源碼推算出了寫法。

 

原理簡述:

如果代碼中引入了spring-cloud-netflix-core(版本1.4.4.RELEASE),則在代碼初始化的時候,會通過RibbonAutoConfiguration類創建一個SpringClientFactory的bean,通過該bean可以獲取服務實例的IP和端口列表。

代碼中的 DomainExtractingServerList對象 是 DynamicServerListLoadBalancer 類中的屬性,該屬性保存的是全量的服務實例,不過卻是私有的,所以只能通過反射來獲取了。

 

 

具體代碼:

 

package com.liuyx;

import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Field;
import java.util.List;

/**
 * Created by liu.yuxiang on 2017/10/12.
 */
@SpringBootApplication//(exclude = {ConfigClientAutoConfiguration.class})
public class PortalZuulApplication {


    public static void main(String[] args) {
        ApplicationContext ctx = new SpringApplicationBuilder(PortalZuulApplication.class).web(true).run(args);

        SpringClientFactory springClientFactory = ctx.getBean(SpringClientFactory.class);
        ILoadBalancer loadBalancer = springClientFactory.getLoadBalancer("[服務名]");
        List<Server> servers = loadBalancer.getReachableServers();
        for(Server server:servers){
            //如果服務有設置zone,此處獲取的可能並不是所有的實例
            System.out.println("---:"+server.getHostPort());
        }

        DynamicServerListLoadBalancer<DiscoveryEnabledServer> dynamicServerListLoadBalancer = (DynamicServerListLoadBalancer)loadBalancer;

        ServerList<DiscoveryEnabledServer> serverListImpl = dynamicServerListLoadBalancer.getServerListImpl();

        DomainExtractingServerList domainExtractingServerList1 = (DomainExtractingServerList) serverListImpl;

        try {
            Field field = domainExtractingServerList1.getClass().getDeclaredField("list");
            field.setAccessible(true);
            ServerList<DiscoveryEnabledServer> list = (ServerList<DiscoveryEnabledServer>)field.get(domainExtractingServerList1);

            for(DiscoveryEnabledServer server:list.getUpdatedListOfServers()){
                //此處獲取的是所有的實例
                System.out.println("%%%:"+server.getHostPort());
            }

            /*for(DiscoveryEnabledServer server:list.getInitialListOfServers()){
                System.out.println("+++:"+server.getHostPort());
            }*/
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

代碼中的"[服務名]"請換成你自己的。

因項目中使用了zone(即 eureka.instance.metadata-map.zone=xxx),所以只能通過反射,才能獲取真正的所有服務實例,否則只能獲取zone為xxx的服務實例。

如果還不明白,參看 區域親和

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM