最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringCloud超詳細(xì)講解負(fù)載均衡組件Ribbon源碼

 更新時(shí)間:2022年07月16日 14:05:14   作者:_時(shí)光煮雨  
在微服務(wù)中,對(duì)服務(wù)進(jìn)行拆分之后,必然會(huì)帶來(lái)微服務(wù)之間的通信需求,而每個(gè)微服務(wù)為了保證高可用性,又會(huì)去部署集群,那么面對(duì)一個(gè)集群微服務(wù)進(jìn)行通信的時(shí)候,如何進(jìn)行負(fù)載均衡也是必然需要考慮的問(wèn)題

前言

上一篇文章中我們通過(guò)自己開(kāi)發(fā)了一個(gè)負(fù)載均衡組件,實(shí)現(xiàn)了隨機(jī)算法的負(fù)載均衡功能,如果要實(shí)現(xiàn)其他算法,還需要修改代碼增加相應(yīng)的功能。這一篇文章,我們將介紹一個(gè)更簡(jiǎn)單的負(fù)載均衡實(shí)現(xiàn),使用**@LoadBalanced**注解實(shí)現(xiàn)負(fù)載均衡的功能。

項(xiàng)目實(shí)戰(zhàn)

創(chuàng)建項(xiàng)目

同樣的,我們的項(xiàng)目現(xiàn)在依然有一個(gè)registry注冊(cè)中心,一個(gè)provider服務(wù)提供者,接下來(lái),我們?cè)俅涡薷囊幌耤onsumer服務(wù)消費(fèi)者的代碼:

@EnableEurekaClient
@SpringBootApplication
@RestController
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
    @Autowired
    DiscoveryClient discoveryClient;
    @Autowired
    RestTemplate restTemplate;
    @GetMapping("/hello2")
    public String hello2(String name) {
        String returnInfo = restTemplate.getForObject(  "http://provider/hello?name={1}", String.class, name);
        return returnInfo;
    }
}

在這個(gè)版本,同樣的,還是創(chuàng)建RestTemplate Bean對(duì)象,不同的是上面僅僅增加了@LoadBalanced注解。

啟動(dòng)項(xiàng)目驗(yàn)證

依然正確返回了結(jié)果!

太神奇了吧,比我們自己開(kāi)發(fā)的負(fù)載均衡組件簡(jiǎn)單太多了吧,僅僅在restTemplate() 方法上面增加了一個(gè)@LoadBalanced注解,怎么就實(shí)現(xiàn)的呢?廢話不說(shuō),為了一探究竟,扒一扒源碼吧!

源碼分析

首先,點(diǎn)擊@LoadBalanced注解進(jìn)去,沒(méi)有什么特別之處,那么我們?cè)谙胂?,Spring在創(chuàng)建Bean實(shí)例的時(shí)候,注解在什么地方起了作用?什么?不知道?翻一下這篇文章吧:

肝了兩周,一張圖解鎖Spring核心源碼

通過(guò)回顧Spring啟動(dòng)以及Bean的生命周期創(chuàng)建過(guò)程,我們就會(huì)發(fā)現(xiàn)加上@LoadBalancer注解后,項(xiàng)目啟動(dòng)時(shí)就會(huì)加載LoadBalancerAutoConfiguration這個(gè)配置類(lèi)(通過(guò)spring-cloud-commons包下面的的spring.factories)。通過(guò)查看該配置類(lèi)源碼,發(fā)現(xiàn)其有個(gè)靜態(tài)內(nèi)部類(lèi)LoadBalancerInterceptorConfig,其內(nèi)部又創(chuàng)建了一個(gè)負(fù)載均衡攔截器:LoadBalancerInterceptor,該攔截器包含有一個(gè)loadBalancerClient參數(shù):

@ConditionalOnMissingClass({"org.springframework.retry.support.RetryTemplate"})
    static class LoadBalancerInterceptorConfig {
        LoadBalancerInterceptorConfig() {
        }
        @Bean
        public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
            return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
        }
        @Bean
        @ConditionalOnMissingBean
        public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
            return (restTemplate) -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
        }
    }

我們繼續(xù)點(diǎn)擊LoadBalancerInterceptor類(lèi)進(jìn)入,發(fā)現(xiàn)intercept方法,該方法中調(diào)用了LoadBalancerClient的execute方法,

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }

LoadBalancerClient是一個(gè)接口,點(diǎn)擊進(jìn)去我們發(fā)現(xiàn)其實(shí)現(xiàn)類(lèi)是RibbonLoadBalancerClient,查看其繼承關(guān)系:

通過(guò)接口中的方法名稱(chēng),我們可以猜想,choose方法就是選擇其中服務(wù)列表中其中一個(gè)服務(wù),reconstructURI方法就是重新構(gòu)造請(qǐng)求的URI。

選擇服務(wù)

choose方法是在RibbonLoadBalancerClient實(shí)現(xiàn)類(lèi)中實(shí)現(xiàn)的

    public ServiceInstance choose(String serviceId, Object hint) {
        Server server = this.getServer(this.getLoadBalancer(serviceId), hint);
        return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
    }

在這個(gè)方法中,先調(diào)用 getServer 方法獲取服務(wù),這個(gè)方法最終會(huì)調(diào)用 ILoadBalancer 接口的 chooseServer 方法,而 ILoadBalancer 接口的實(shí)現(xiàn)類(lèi)默認(rèn)是ZoneAwareLoadBalancer。

ZoneAwareLoadBalancer 繼承自 DynamicServerListLoadBalancer ,而在 DynamicServerListLoadBalancer 的構(gòu)造方法中,調(diào)用了 this.restOfInit(clientConfig);在restOfInit這個(gè)方法中,通過(guò) this.updateListOfServers()來(lái)獲取服務(wù)列表;

而在chooseServer ()方法中,就會(huì)根據(jù)負(fù)載均衡算法,選擇其中一個(gè)服務(wù)并返回:

 BaseLoadBalancer zoneLoadBalancer = this.getLoadBalancer(zone);
 server = zoneLoadBalancer.chooseServer(key);

地址替換

選擇其中一個(gè)服務(wù)信息后,怎么將接口從 http://provider/hello 變?yōu)?http://localhost:8003/hello 呢?還記得上面我們說(shuō)的reconstructURI方法嗎?通過(guò)配置類(lèi)LoadBalancerAutoConfiguration加載后,會(huì)注入LoadBalancerInterceptor攔截器,該攔截器會(huì)攔截我們的請(qǐng)求,并對(duì)請(qǐng)求地址進(jìn)行處理,重構(gòu)方法的具體實(shí)現(xiàn)在 LoadBalancerContext 類(lèi)的 reconstructURIWithServer 方法中

public URI reconstructURIWithServer(Server server, URI original) {
        String host = server.getHost();
        int port = server.getPort();
        String scheme = server.getScheme();
        if (host.equals(original.getHost()) && port == original.getPort() && scheme == original.getScheme()) {
            return original;
        } else {
            if (scheme == null) {
                scheme = original.getScheme();
            }
            if (scheme == null) {
                scheme = (String)this.deriveSchemeAndPortFromPartialUri(original).first();
            }
            try {
                StringBuilder sb = new StringBuilder();
                sb.append(scheme).append("://");
                if (!Strings.isNullOrEmpty(original.getRawUserInfo())) {
                    sb.append(original.getRawUserInfo()).append("@");
                }
                sb.append(host);
                if (port >= 0) {
                    sb.append(":").append(port);
                }
                sb.append(original.getRawPath());
                if (!Strings.isNullOrEmpty(original.getRawQuery())) {
                    sb.append("?").append(original.getRawQuery());
                }
                if (!Strings.isNullOrEmpty(original.getRawFragment())) {
                    sb.append("#").append(original.getRawFragment());
                }
                URI newURI = new URI(sb.toString());
                return newURI;
            } catch (URISyntaxException var8) {
                throw new RuntimeException(var8);
            }
        }
    }

可以看到該方法中,將原始的請(qǐng)求地址original,替換成了選取的服務(wù)的IP和端口。并最終調(diào)用該服務(wù)的接口方法。

看到這里,再想想我們上一章的內(nèi)容,是不是有異曲同工之妙?

總結(jié)

通過(guò)添加@LoadBalanced注解,就及其簡(jiǎn)單的實(shí)現(xiàn)了負(fù)載均衡的功能,與其說(shuō)是Ribbon的強(qiáng)大,不如說(shuō)是Spring的強(qiáng)大,Spring在整個(gè)上下文創(chuàng)建過(guò)程中,在不同的時(shí)機(jī)開(kāi)放了一個(gè)又一個(gè)的接口,這就為各種組件的繼承提供了遍歷,同時(shí)也進(jìn)一步促進(jìn)了Spring生態(tài)的快速發(fā)展。

到此這篇關(guān)于SpringCloud超詳細(xì)講解負(fù)載均衡組件的文章就介紹到這了,更多相關(guān)SpringCloud負(fù)載均衡組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 手寫(xiě)mybatis完整sql插件問(wèn)題及實(shí)現(xiàn)思路

    手寫(xiě)mybatis完整sql插件問(wèn)題及實(shí)現(xiàn)思路

    大家在使用mybatis的過(guò)程中,mysql日志功能一般不會(huì)直接放到數(shù)據(jù)庫(kù)中執(zhí)行的,今天小編重點(diǎn)給大家分享手寫(xiě)mybatis完整sql插件問(wèn)題及實(shí)現(xiàn)思路,對(duì)mybatis完整sql插件相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-05-05
  • Spring MVC 啟動(dòng)過(guò)程源碼分析詳解

    Spring MVC 啟動(dòng)過(guò)程源碼分析詳解

    這篇文章主要介紹了Spring MVC 啟動(dòng)過(guò)程源碼分析詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • SpringBoot整合Kotlin構(gòu)建Web服務(wù)的方法示例

    SpringBoot整合Kotlin構(gòu)建Web服務(wù)的方法示例

    這篇文章主要介紹了SpringBoot整合Kotlin構(gòu)建Web服務(wù)的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • java連接池Druid獲取連接getConnection示例詳解

    java連接池Druid獲取連接getConnection示例詳解

    這篇文章主要為大家介紹了java連接池Druid獲取連接getConnection示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • MyBatis根據(jù)條件批量修改字段的方式

    MyBatis根據(jù)條件批量修改字段的方式

    這篇文章主要介紹了MyBatis根據(jù)條件批量修改字段的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java parseInt解釋加方法示例

    Java parseInt解釋加方法示例

    使用此方法得到的原始數(shù)據(jù)類(lèi)型的一個(gè)特定的字符串。 parseXxx()是一個(gè)靜態(tài)方法,可以有一個(gè)參數(shù)或兩個(gè)
    2013-11-11
  • MyBatisPlus超詳細(xì)分析條件查詢

    MyBatisPlus超詳細(xì)分析條件查詢

    這篇文章主要介紹了MyBatisPlus條件查詢的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Java GUI制作簡(jiǎn)單的管理系統(tǒng)

    Java GUI制作簡(jiǎn)單的管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java GUI制作簡(jiǎn)單的管理系統(tǒng)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java實(shí)現(xiàn)XML文件學(xué)生通訊錄

    Java實(shí)現(xiàn)XML文件學(xué)生通訊錄

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)XML文件學(xué)生通訊錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 深入了解JAVA 虛引用

    深入了解JAVA 虛引用

    這篇文章主要介紹了JAVA 虛引用的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JAVA,感興趣的朋友可以了解下
    2020-08-08

最新評(píng)論

海林市| 双流县| 莫力| 米脂县| 哈尔滨市| 德安县| 铜川市| 金门县| 平利县| 水富县| 大城县| 梨树县| 逊克县| 静海县| 潞城市| 甘南县| 奎屯市| 鄂托克旗| 靖安县| 防城港市| 天全县| 中江县| 汕头市| 栖霞市| 萝北县| 哈密市| 贵州省| 丹阳市| 和龙市| 汉中市| 内黄县| 秦皇岛市| 岳普湖县| 治多县| 宜黄县| 定日县| 鄢陵县| 个旧市| 赤水市| 新竹县| 吉首市|