俯瞰Dubbo全局,閱讀源碼前必須掌握這些!!

寫在前面

在上一篇《冰河開始對Dubbo下手了!》一文中,我們重點介紹了為何要學習Dubbo,而且還是要深入理解Dubbo的原理和核心源碼。既然是要寫深度解析Dubbo源碼的系列專題,我們首先要做的就是搭建一套Dubbo的源碼環境,正所謂「工欲善其事,必先利其器」。但是,為了更好的理解Dubbo,我將本文重點分成三個部分:Dubbo中的核心角色、搭建Dubbo源碼環境、Dubbo核心模塊說明、運行Dubbo的示例程序 四個部分。說干就干,上重點。

註:本系列專題,我是基於Dubbo 2.7.8版本進行源碼分析的。

文章已收錄到:

//github.com/sunshinelyz/technology-binghe

//gitee.com/binghe001/technology-binghe

Dubbo中的核心角色

為了更好的說明Dubbo中的核心角色,這裡,我就直接引用一張Dubbo的依賴關係圖。

註:圖片來自Dubbo官網。

從Dubbo的依賴關係圖中,我們可以看出,Dubbo主要由四部分構成:Registry、Provider、Consumer和Monitor 。接下來,我們就分別對這四部分進行簡單的介紹。

  • Registry,註冊中心。在Dubbo中,註冊中心負責服務的註冊與發現,主要就是針對服務地址的註冊與查找。值得一提的是,在Dubbo中,Provider和Consumer只有在服務啟動的時候與註冊中心進行交互。之後,註冊中心通過長連接的形式來感知Provider的存在,如果Provider宕機或不可用,註冊中心就會立即推送相關的事件來告知Consumer。
  • Provider,服務的提供者。Provider在啟動的時候,會向註冊中心註冊自己的相關服務,主要是通過將自身的服務地址和相關的配置信息封裝成URL添加到Zookeeper等服務中。
  • Consumer,服務的消費者。Consumer在啟動的時候,會向註冊中心訂閱其關注的服務。主要是向Zookeeper等服務中獲取Provider註冊的URL,並且在Zookeeper等服務中添加相應的監聽器。獲取到Provider註冊的URL之後,Consumer就會通過負載均衡算法從獲取的多個Provider中選擇一個,並與其建立連接,發起RPC調用。如果Zookeeper等服務中註冊的Provider發生了變更,Consumer就會通過在註冊中心中添加的監聽器來獲取最新的Provider信息。而且Consumer會緩存Provider的信息,如果Consumer與Provider一旦建立起連接,即使註冊中心宕機或不可用,也不會影響Consumer和Provider之間的交互。
  • Monitor:監控中心。主要用來統計Dubbo服務的調用次數和調用的時間。在Dubbo的核心架構中,監控中心不是必需的,監控中心宕機或不可用不會影響Dubbo的整體服務。

好了,對於Dubbo的核心角色我們就介紹到這兒,更多的信息,小夥伴們可以參見Dubbo的官方文檔。

搭建Dubbo源碼環境

我們可以使用如下命令將github的源碼下載的本地。

git clone //github.com/apache/dubbo.git

接下來,將Dubbo的源碼切換到2.7.8

git checkout -b dubbo-2.7.8 dubbo-2.7.8

使用Maven進行編譯

mvn clean install -Dmaven.test.skip=true 

轉換成IDEA項目,這裡我使用的是IDEA分析Dubbo源碼。

mvn idea:idea

接下來,我們就可以將Dubbo源碼導入到IDEA了。

說了這麼多,其中還有一種方式就是通過瀏覽器直接下載Dubbo 2.7.8的源碼到本地。

在瀏覽器中打開鏈接://github.com/apache/dubbo/releases/tag/dubbo-2.7.8 下載Dubbo源碼。

這裡下載zip壓縮包和tar.gz壓縮包均可,下載到本地後解壓,將其導入到IDEA中即可。

導入完成後,我們看到的項目結構如下所示。

接下來,我們就對Dubbo源碼中的核心模塊進行簡單的介紹。

Dubbo核心模塊說明

dubbo-common模塊

Dubbo的公共模塊,提供了Dubbo SPI的實現、時間輪的實現、動態編譯等通用的功能。

dubbo-remoting模塊

Dubbo的遠程通信模塊,其中,dubbo-remoting-api是對整個模塊的核心抽象,其他子模塊基於其他開源框架對dubbo-remoting-api進行實現。

dubbo-rpc模塊

Dubbo的RPC模塊,依賴dubbo-remoting模塊。其中,dubbo-remoting-api是整個dubbo-rpc模塊的核心抽象,其他模塊是對dubbo-remoting-api的實現。

dubbo-registry模塊

Dubbo中與註冊中心交互的模塊。其中dubbo-registry-api是整個dubbo-registry的核心抽象,其他模塊是對dubbo-registry-api的具體實現。

dubbo-config模塊

Dubbo中解析對外暴露的配置的模塊。其中,dubbo-config-api 子模塊負責處理以API 方式使用Dubbo時的相關配置,dubbo-config-spring 子模塊負責處理與 Spring 集成使用時的相關配置方式。

dubbo-metadata模塊

Dubbo中的元數據模塊。其中,dubbo-metadata-api是對整個dubbo-metadata的抽象,其他模塊是對dubbo-metadata-api的實現。

dubbo-configcenter模塊

Dubbo的配置中心模塊,其中,提供了多種服務發現的方式並接入了多種服務發現組件。

dubbo-monitor模塊

Dubbo 的監控模塊,主要用於統計服務調用次數、調用時間以及實現調用鏈跟蹤的服務。

dubbo-cluster模塊

Dubbo的集群管理模塊,主要提供負載均衡、容錯、路由等功能。

運行Dubbo示例程序

在Dubbo源碼中,有一個示例程序模塊dubbo-demo,在運行dubbo-demo模塊中的示例前,我們先在本地啟動一個Zookeeper作為註冊中心。

註:小夥伴們可以自行到Apache官網下載Zookeeper。

Dubbo示例程序結構

Dubbo提供的示例程序的總體結構如下所示。

我們來看看dubbo-demo下有哪些模塊。

  • dubbo-demo-interface:Dubbo示例定義的業務接口。
  • dubbo-demo-xml:提供了基於Spring XML的使用示例。
  • dubbo-demo-annotation:提供了基於Spring註解方式的使用示例。
  • dubbo-demo-api:提供了以API方式使用Dubbo的示例。

其中,dubbo-demo-xml、dubbo-demo-annotation和dubbo-demo-api模塊都是依賴dubbo-demo-interface模塊的。

接下來,我們就對dubbo-demo-interface模塊和dubbo-demo-annotation模塊的核心代碼進行簡單的介紹,並運行相關的示例程序。小夥伴們可自行分析和運行dubbo-demo-xml和dubbo-demo-api中的示例程序並運行相關的代碼。

(1)dubbo-demo-interface:定義了業務接口。

其中,DemoService接口的核心代碼如下所示。

package org.apache.dubbo.demo;
import java.util.concurrent.CompletableFuture;
public interface DemoService {
    //同步調用
    String sayHello(String name);
    //異步調用
    default CompletableFuture<String> sayHelloAsync(String name) {
        return CompletableFuture.completedFuture(sayHello(name));
    }
}

(2)dubbo-demo-annotation:提供了基於Spring註解的示例程序。

Provider代碼

我們先來看dubbo-demo-annotation-provider模塊,也就是服務的提供者。其DemoServiceImpl的代碼如下所示。

@DubboService
public class DemoServiceImpl implements DemoService {
    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);

    @Override
    public String sayHello(String name) {
        logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
    }

    @Override
    public CompletableFuture<String> sayHelloAsync(String name) {
        return null;
    }
}

Application類的代碼如下所示。

public class Application {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
        context.start();
        System.in.read();
    }

    @Configuration
    @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
    @PropertySource("classpath:/spring/dubbo-provider.properties")
    static class ProviderConfiguration {
        @Bean
        public RegistryConfig registryConfig() {
            RegistryConfig registryConfig = new RegistryConfig();
            registryConfig.setAddress("zookeeper://127.0.0.1:2181");
            return registryConfig;
        }
    }
}

Consumer代碼

接下來,我們來看看dubbo-demo-annotation-consumer模塊的代碼,也就是服務消費者的示例代碼。其中,DemoServiceComponent類的代碼如下所示。

@Component("demoServiceComponent")
public class DemoServiceComponent implements DemoService {
    @DubboReference
    private DemoService demoService;

    @Override
    public String sayHello(String name) {
        return demoService.sayHello(name);
    }
    @Override
    public CompletableFuture<String> sayHelloAsync(String name) {
        return null;
    }
}

Application類的代碼如下所示。

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
        context.start();
        DemoService service = context.getBean("demoServiceComponent", DemoServiceComponent.class);
        String hello = service.sayHello("world");
        System.out.println("result :" + hello);
    }

    @Configuration
    @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.consumer.comp")
    @PropertySource("classpath:/spring/dubbo-consumer.properties")
    @ComponentScan(value = {"org.apache.dubbo.demo.consumer.comp"})
    static class ConsumerConfiguration {

    }
}

運行Dubbo示例程序

我們先在本地啟動Zookeeper,然後分別運行dubbo-demo-annotation-provider模塊的Application類和dubbo-demo-annotation-consumer模塊的Application類。

此時在IDEA的控制台會輸出如下信息。

result :Hello world, response from provider: 192.168.0.5:20880

Dubbo總結

到這裡,我們介紹了Dubbo中的核心角色,如何搭建Dubbo源碼環境,對Dubbo源碼中的核心模塊進行了簡單的說明,並簡單的分析了Dubbo的示例程序並運行了示例程序。其中,在介紹和運行示例程序時,我們重點介紹了dubbo-demo-annotation示例模塊,小夥伴們可自行分析和運行其他示例模塊。在後續的文章中分析源碼時,我們也主要是通過debug Dubbo的示例程序的方式進行。

好了,今天就到這兒吧,我是冰河,大家有啥問題可以在下方留言,也可以加我微信:sun_shine_lyz,一起交流技術,一起進階,一起牛逼~~