欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud超詳細講解負載均衡組件Ribbon源碼

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

前言

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

項目實戰(zhàn)

創(chuàng)建項目

同樣的,我們的項目現(xiàn)在依然有一個registry注冊中心,一個provider服務(wù)提供者,接下來,我們再次修改一下consumer服務(wù)消費者的代碼:

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

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

啟動項目驗證

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

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

源碼分析

首先,點擊@LoadBalanced注解進去,沒有什么特別之處,那么我們在想想,Spring在創(chuàng)建Bean實例的時候,注解在什么地方起了作用?什么?不知道?翻一下這篇文章吧:

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

通過回顧Spring啟動以及Bean的生命周期創(chuàng)建過程,我們就會發(fā)現(xiàn)加上@LoadBalancer注解后,項目啟動時就會加載LoadBalancerAutoConfiguration這個配置類(通過spring-cloud-commons包下面的的spring.factories)。通過查看該配置類源碼,發(fā)現(xiàn)其有個靜態(tài)內(nèi)部類LoadBalancerInterceptorConfig,其內(nèi)部又創(chuàng)建了一個負載均衡攔截器:LoadBalancerInterceptor,該攔截器包含有一個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ù)點擊LoadBalancerInterceptor類進入,發(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是一個接口,點擊進去我們發(fā)現(xiàn)其實現(xiàn)類是RibbonLoadBalancerClient,查看其繼承關(guān)系:

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

選擇服務(wù)

choose方法是在RibbonLoadBalancerClient實現(xiàn)類中實現(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));
    }

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

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

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

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

地址替換

選擇其中一個服務(wù)信息后,怎么將接口從 http://provider/hello 變?yōu)?http://localhost:8003/hello 呢?還記得上面我們說的reconstructURI方法嗎?通過配置類LoadBalancerAutoConfiguration加載后,會注入LoadBalancerInterceptor攔截器,該攔截器會攔截我們的請求,并對請求地址進行處理,重構(gòu)方法的具體實現(xiàn)在 LoadBalancerContext 類的 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);
            }
        }
    }

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

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

總結(jié)

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

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

相關(guān)文章

  • SpringBoot處理跨域請求的四種方法

    SpringBoot處理跨域請求的四種方法

    在現(xiàn)代Web應(yīng)用中,由于安全性和隱私的考慮,瀏覽器限制了從一個域向另一個域發(fā)起的跨域HTTP請求,解決這個問題的一種常見方式是實現(xiàn)跨域資源共享(CORS),SpringBoot提供了多種方式來處理跨域請求,本文將介紹其中的幾種方法,感興趣的朋友可以參考下
    2023-12-12
  • IntelliJ IDEA失焦自動重啟服務(wù)的解決方法

    IntelliJ IDEA失焦自動重啟服務(wù)的解決方法

    在使用 IntelliJ IDEA運行 SpringBoot 項目時,你可能會遇到一個令人困擾的問題,一旦你的鼠標指針離開當前IDE窗口,點擊其他位置時, IDE 窗口會失去焦點,你的 SpringBoot 服務(wù)就會自動重啟,所以本文給大家介紹了IntelliJ IDEA失焦自動重啟服務(wù)的解決方法
    2023-10-10
  • Java獲取當?shù)氐娜粘鋈章鋾r間代碼分享

    Java獲取當?shù)氐娜粘鋈章鋾r間代碼分享

    這篇文章主要介紹了Java獲取當?shù)氐娜粘鋈章鋾r間代碼分享,國外猿友寫的一個類,需要的朋友可以參考下
    2014-06-06
  • SpringBoot構(gòu)建ORM框架的方法步驟

    SpringBoot構(gòu)建ORM框架的方法步驟

    本文主要介紹了SpringBoot構(gòu)建ORM框架的方法步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Spring Boot如何通過java -jar啟動

    Spring Boot如何通過java -jar啟動

    大家開發(fā)的基于Spring Boot 的應(yīng)用 ,jar形式, 發(fā)布的時候,絕大部分都是使用java -jar 啟動。本文主要介紹了Spring Boot如何通過java -jar啟動,一起來了解一下
    2021-05-05
  • Spring?@Conditional通過條件控制bean注冊過程

    Spring?@Conditional通過條件控制bean注冊過程

    這篇文章主要為大家介紹了Spring?@Conditional通過條件控制bean注冊過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • java中如何使用BufferedImage判斷圖像通道順序并轉(zhuǎn)RGB/BGR

    java中如何使用BufferedImage判斷圖像通道順序并轉(zhuǎn)RGB/BGR

    這篇文章主要介紹了java中如何BufferedImage判斷圖像通道順序并轉(zhuǎn)RGB/BGR的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Spring中@Scope注解用法解析

    Spring中@Scope注解用法解析

    這篇文章主要介紹了Spring中@Scope注解用法解析,@Scope注解主要作用是調(diào)節(jié)Ioc容器中的作用域,在Spring IoC容器中主要有以下五種作用域,需要的朋友可以參考下
    2023-11-11
  • 最詳細的文件上傳下載實例詳解(推薦)

    最詳細的文件上傳下載實例詳解(推薦)

    在Web應(yīng)用系統(tǒng)開發(fā)中,文件上傳和下載功能是非常常用的功能,今天來講一下JavaWeb中的文件上傳和下載功能的實現(xiàn)。非常不錯,具有參考借鑒價值,感興趣的朋友一起看下吧
    2016-07-07
  • Java編程求二叉樹的鏡像兩種方法介紹

    Java編程求二叉樹的鏡像兩種方法介紹

    這篇文章主要介紹了Java編程求二叉樹的鏡像兩種方法介紹,分享了兩種方法,遞歸與非遞歸,每種方法又分別介紹了兩種解決思路,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11

最新評論