Dubbo Spring Cloud 重塑微服務治理

原文連接: Dubbo Spring Cloud 重塑微服務治理,來自於微信公衆號: 次靈均閣

摘要

在 Java 微服務生態中,Spring Cloud1 成爲了開發人員的首選技術棧,然而隨着實踐的深刻和運用規模的擴大,你們逐漸意識到 Spring Cloud 的侷限性。在服務治理方面,相較於 Dubbo2 而言,Spring Cloud 並不成熟。遺憾的是,Dubbo 每每被部分開發者片面地視做服務治理的 RPC 框架,而非微服務基礎設施。即便是那些有意將 Spring Cloud 遷移至 Dubbo 的小夥伴,當面對其中遷移和改造的成本時,不免望而卻步。慶幸的是,Dubbo 生態體系已發生巨大變化,Dubbo Spring Cloud 做爲 Spring Cloud Alibaba3 的最核心組件,徹底地擁抱 Spring Cloud 技術棧,不但無縫地整合 Spring Cloud 註冊中心,包括 Nacos4、Eureka5、Zookeeper6 以及 Consul7,並且徹底地兼容 Spring Cloud Open Feign8 以及 @LoadBalanced RestTemplate,本文將討論 Dubbo Spring Cloud 對 Spring Cloud 技術棧所帶來的革命性變化。html

注:因爲 Spring Cloud 技術棧涵蓋的特性衆多,所以本文討論的範圍僅限於服務治理部分。

簡介

Dubbo Spring Cloud 基於 Dubbo Spring Boot 2.7.19 和 Spring Cloud 2.x 開發,不管開發人員是 Dubbo 用戶仍是 Spring Cloud 用戶,都能輕鬆地駕馭,並以接近「零」成本的代價使應用向上遷移。Dubbo Spring Cloud 致力於簡化 Cloud Native 開發成本,提升研發效能以及提高應用性能等目的。java

2019年4月19日,Dubbo Spring Cloud 首個 Preview Release,隨同 Spring Cloud Alibaba 0.2.2.RELEASE0.9.0.RELEASE 一同發佈10,分別對應 Spring Cloud Finchley11 與 Greenwich12 (下文分別簡稱爲 「F」 版 和 「G」 版) 。git

版本支持

因爲 Spring 官方宣佈 Spring Cloud Edgware(下文簡稱爲 「E」 版) 將在 2019 年 8 月 1 號後中止維護13,所以,目前 Dubbo Spring Cloud 發佈版本並未對 「E」 版提供支持,僅爲 「F」 版 和 「G」 版開發,同時也建議和鼓勵 Spring Cloud 用戶更新至 「F」 版 或 「G」 版。github

同時,Dubbo Spring Cloud 基於 Apache Dubbo Spring Boot 2.7.1 開發(最低 Java 版本爲 1.8),提供完整的 Dubbo 註解驅動、外部化配置以及 Production-Ready 的特性,詳情請參考:https://github.com/apache/inc...web

如下表格將說明 Dubbo Spring Cloud 版本關係映射關係:算法

Spring Cloud Spring Cloud Alibaba Spring Boot Dubbo Spring Boot
Finchley 0.2.2.RELEASE 2.0.x 2.7.1
Greenwich 0.9.0.RELEASE 2.1.x 2.7.1
Edgware 0.1.2.RELEASE 1.5.x Dubbo Spring Cloud 不支持該版本

功能特性

因爲 Dubbo Spring Cloud 構建在原生的 Spring Cloud 之上,其服務治理方面的能力可認爲是 Spring Cloud Plus,不只徹底覆蓋 Spring Cloud 原生特性13,並且提供更爲穩定和成熟的實現,特性比對以下表所示:spring

功能組件 Spring Cloud Dubbo Spring Cloud
分佈式配置(Distributed configuration) Git、Zookeeper、Consul、JDBC Spring Cloud 分佈式配置 + Dubbo 配置中心14
服務註冊與發現(Service registration and discovery) Eureka、Zookeeper、Consul Spring Cloud 原生註冊中心15 + Dubbo 原生註冊中心16
負載均衡(Load balancing) Ribbon(隨機、輪詢等算法) Dubbo 內建實現(隨機、輪詢等算法 + 權重等特性)
服務熔斷(Circuit Breakers) Spring Cloud Hystrix Spring Cloud Hystrix + Alibaba Sentinel17
服務調用(Service-to-service calls) Open Feign、RestTemplate Spring Cloud 服務調用 + Dubbo @Reference
鏈路跟蹤(Tracing) Spring Cloud Sleuth18 + Zipkin19 Zipkin、opentracing 等

高亮特性

1. Dubbo 使用 Spring Cloud 服務註冊與發現

Dubbo Spring Cloud 基於 Spring Cloud Commons 抽象實現 Dubbo 服務註冊與發現,應用只需增添外部化配置屬性 「dubbo.registry.address = spring-cloud://localhost」,就能輕鬆地橋接到全部原生 Spring Cloud 註冊中心,包括:apache

  • Nacos
  • Eureka
  • Zookeeper
  • Consul
Dubbo Spring Cloud 將在下個版本支持 Spring Cloud 註冊中心與 Dubbo 註冊中心並存,提供雙註冊機制,實現無縫遷移。

2. Dubbo 做爲 Spring Cloud 服務調用

默認狀況,Spring Cloud Open Feign 以及 @LoadBalanced RestTemplate 做爲 Spring Cloud 的兩種服務調用方式。Dubbo Spring Cloud 爲其提供了第三種選擇,即 Dubbo 服務將做爲 Spring Cloud 服務調用的同等公民出現,應用可經過 Apache Dubbo 註解 @Service@Reference 暴露和引用 Dubbo 服務,實現服務間多種協議的通信。同時,也能夠利用 Dubbo 泛化接口輕鬆實現服務網關。編程

3. Dubbo 服務自省

Dubbo Spring Cloud 引入了全新的服務治理特性 - 服務自省(Service Introspection),其設計目的在於最大化減輕註冊中心負載,去 Dubbo 註冊元信息中心化。假設一個 Spring Cloud 應用引入 Dubbo Spring Boot Starter,並暴露 N 個 Dubbo 服務,以 Dubbo Nacos 註冊中心 爲例,當前應用將註冊 N+1 個 Nacos 應用,除 Spring Cloud 應用自己以前,其他 N 個應用均來自於 Dubbo 服務,當 N 越大時,註冊中心負載越重。所以,Dubbo Spring Cloud 應用對註冊中心的負載至關於傳統 Dubbo 的 N 分之一,在不增長基礎設施投入的前提下,理論上,使其集羣規模擴大 N 倍。固然,將來的 Dubbo 也將提供服務自省的能力。bootstrap

4. Dubbo 遷移 Spring Cloud 服務調用

儘管 Dubbo Spring Cloud 徹底地保留了原生 Spring Cloud 服務調用特性,不過 Dubbo 服務治理的能力是 Spring Cloud Open Feign 所不及的,如高性能、高可用以及負載均衡穩定性等方面。所以,建議開發人員將 Spring Cloud Open Feign 或者 @LoadBalanced RestTemplate 遷移爲 Dubbo 服務。考慮到遷移過程並不是一蹴而就,所以,Dubbo Spring Cloud 提供了方案,即 @DubboTransported 註解。該註解可以幫助服務消費端的 Spring Cloud Open Feign 接口以及 @LoadBalanced RestTemplate Bean 底層走 Dubbo 調用(可切換 Dubbo 支持的協議),而服務提供方則只需在原有 @RestController 類上追加 Dubbo @Servce 註解(須要抽取接口)便可,換言之,在不調整 Feign 接口以及 RestTemplate URL 的前提下,實現無縫遷移。若是遷移時間充分的話,建議使用 Dubbo 服務重構系統中的原生 Spring Cloud 服務的定義。

簡單示例

開發 Dubbo Spring Cloud 應用的方法與傳統 Dubbo 或 Spring Cloud 應用相似,按照如下步驟就能完整地實現Dubbo 服務提供方和消費方的應用,完整的示例代碼請訪問一下資源:

定義 Dubbo 服務接口

Dubbo 服務接口是服務提供方與消費方的遠程通信契約,一般由普通的 Java 接口(interface)來聲明,如 EchoService 接口:

public interface EchoService {

    String echo(String message);
}

爲了確保契約的一致性,推薦的作法是將 Dubbo 服務接口打包在第二方或者第三方的 artifact(jar)中,如以上接口就存放在 artifact spring-cloud-dubbo-sample-api 之中。

對於服務提供方而言,不只經過依賴 artifact 的形式引入 Dubbo 服務接口,並且須要將其實現。對應的服務消費端,一樣地須要依賴該 artifact,並以接口調用的方式執行遠程方法。接下來進一步討論怎樣實現 Dubbo 服務提供方和消費方。

實現 Dubbo 服務提供方

初始化 spring-cloud-dubbo-server-sample Maven 工程

首先,建立 artifactId 名爲 spring-cloud-dubbo-server-sample 的 Maven 工程,並在其 pom.xml 文件中增添
Dubbo Spring Cloud 必要的依賴:

<dependencies>
    <!-- Sample API -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dubbo-sample-api</artifactId>
        <version>${project.version}</version>
    </dependency>

    <!-- Spring Boot dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
    </dependency>

    <!-- Dubbo Spring Cloud Starter -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-dubbo</artifactId>
    </dependency>

    <!-- Spring Cloud Nacos Service Discovery -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>

以上依賴 artifact 說明以下:

  • spring-cloud-dubbo-sample-api : 提供 EchoService 接口的 artifact
  • spring-boot-actuator : Spring Boot Production-Ready artifact,間接引入 spring-boot artifact
  • spring-cloud-starter-dubbo : Dubbo Spring Cloud Starter artifact,間接引入 dubbo-spring-boot-starter 等 artifact
  • spring-cloud-starter-alibaba-nacos-discovery : Nacos Spring Cloud 服務註冊與發現 artifact

值得注意的是,以上 artifact 未指定版本(version),所以,還需顯示地聲明 <dependencyManagement> :

<dependencyManagement>
    <dependencies>
        <!-- Spring Cloud Alibaba dependencies -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>0.9.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
以上完整的 Maven 依賴配置,請參考 spring-cloud-dubbo-server-sample pom.xml 文件

完成以上步驟以後,下一步則是實現 Dubbo 服務

實現 Dubbo 服務

EchoService 做爲暴露的 Dubbo 服務接口,服務提供方 spring-cloud-dubbo-server-sample 須要將其實現:

@org.apache.dubbo.config.annotation.Service
class EchoServiceImpl implements EchoService {

    @Override
    public String echo(String message) {
        return "[echo] Hello, " + message;
    }
}

其中,@org.apache.dubbo.config.annotation.Service 是 Dubbo 服務註解,僅聲明該 Java 服務(本地)實現爲 Dubbo 服務。
所以,下一步須要將其配置 Dubbo 服務(遠程)。

配置 Dubbo 服務提供方

在暴露 Dubbo 服務方面,推薦開發人員外部化配置的方式,即指定 Java 服務實現類的掃描基準包。

Dubbo Spring Cloud 繼承了 Dubbo Spring Boot 的外部化配置特性,也能夠經過標註 @DubboComponentScan 來實現基準包掃描。

同時,Dubbo 遠程服務須要暴露網絡端口,並設定通信協議,完整的 YAML 配置以下所示:

dubbo:
  scan:
    # dubbo 服務掃描基準包
    base-packages: org.springframework.cloud.alibaba.dubbo.bootstrap
  protocol:
    # dubbo 協議
    name: dubbo
    # dubbo 協議端口( -1 表示自增端口,從 20880 開始)
    port: -1
  registry:
    # 掛載到 Spring Cloud 註冊中心
    address: spring-cloud://localhost
    
spring:
  application:
    # Dubbo 應用名稱
    name: spring-cloud-alibaba-dubbo-server
  main:
    # Spring Boot 2.1 須要設定
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      # Nacos 服務發現與註冊配置
      discovery:
        server-addr: 127.0.0.1:8848

以上 YAML 內容,上半部分爲 Dubbo 的配置:

  • dubbo.scan.base-packages : 指定 Dubbo 服務實現類的掃描基準包
  • dubbo.protocol : Dubbo 服務暴露的協議配置,其中子屬性 name 爲協議名稱,port 爲協議端口( -1 表示自增端口,從 20880 開始)
  • dubbo.registry : Dubbo 服務註冊中心配置,其中子屬性 address 的值 "spring-cloud://localhost",說明掛載到 Spring Cloud 註冊中心
當前 Dubbo Spring Cloud 實現必須配置 dubbo.registry.address = spring-cloud://localhost,下一個版本將其配置變爲可選
(參考 issue #592),
而且支持傳統 Dubbo 協議的支持(參考 issue #588

下半部分則是 Spring Cloud 相關配置:

  • spring.application.name : Spring 應用名稱,用於 Spring Cloud 服務註冊和發現。
該值在 Dubbo Spring Cloud 加持下被視做 dubbo.application.name,所以,無需再顯示地配置 dubbo.application.name
  • spring.main.allow-bean-definition-overriding : 在 Spring Boot 2.1 以及更高的版本增長該設定,

由於 Spring Boot 默認調整了 Bean 定義覆蓋行爲。(推薦一個好的 Dubbo 討論 issue #3193

  • spring.cloud.nacos.discovery : Nacos 服務發現與註冊配置,其中子屬性 server-addr 指定 Nacos 服務器主機和端口
以上完整的 YAML 配置文件,請參考 spring-cloud-dubbo-server-sample bootstrap.yaml 文件

完成以上步驟後,還需編寫一個 Dubbo Spring Cloud 引導類。

引導 Dubbo Spring Cloud 服務提供方應用

Dubbo Spring Cloud 引導類與普通 Spring Cloud 應用並沒有差異,以下所示:

@EnableDiscoveryClient
@EnableAutoConfiguration
public class DubboSpringCloudServerBootstrap {

    public static void main(String[] args) {
        SpringApplication.run(DubboSpringCloudServerBootstrap.class);
    }
}

在引導 DubboSpringCloudServerBootstrap 以前,請提早啓動 Nacos 服務器。
DubboSpringCloudServerBootstrap 啓動後,將應用 spring-cloud-dubbo-server-sample 將出如今 Nacos 控制檯界面。

當 Dubbo 服務提供方啓動後,下一步實現一個 Dubbo 服務消費方。

實現 Dubbo 服務消費方

因爲 Java 服務就 EchoService、服務提供方應用 spring-cloud-dubbo-server-sample 以及 Nacos 服務器均已準備完畢。Dubbo 服務消費方
只需初始化服務消費方 Maven 工程 spring-cloud-dubbo-client-sample 以及消費 Dubbo 服務。

初始化 spring-cloud-dubbo-client-sample Maven 工程

與服務提供方 Maven 工程類,需添加相關 Maven 依賴:

<dependencyManagement>
    <dependencies>
        <!-- Spring Cloud Alibaba dependencies -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>0.9.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!-- Sample API -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dubbo-sample-api</artifactId>
        <version>${project.version}</version>
    </dependency>

    <!-- Spring Boot dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
    </dependency>

    <!-- Dubbo Spring Cloud Starter -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-dubbo</artifactId>
    </dependency>

    <!-- Spring Cloud Nacos Service Discovery -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>

與應用 spring-cloud-dubbo-server-sample 不一樣的是,當前應用依賴 spring-boot-starter-web,代表它屬於 Web Servlet 應用。

以上完整的 Maven 依賴配置,請參考 spring-cloud-dubbo-client-sample pom.xml 文件

配置 Dubbo 服務消費方

Dubbo 服務消費方配置與服務提供方相似,當前應用 spring-cloud-dubbo-client-sample 屬於純服務消費方,所以,所需的外部化配置更精簡:

dubbo:
  registry:
    # 掛載到 Spring Cloud 註冊中心
    address: spring-cloud://localhost
  cloud:
    subscribed-services: spring-cloud-alibaba-dubbo-server
    
spring:
  application:
    # Dubbo 應用名稱
    name: spring-cloud-alibaba-dubbo-client
  main:
    # Spring Boot 2.1 須要設定
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      # Nacos 服務發現與註冊配置
      discovery:
        server-addr: 127.0.0.1:8848

對比應用 spring-cloud-dubbo-server-sample,除應用名稱 spring.application.name 存在差別外,spring-cloud-dubbo-client-sample
新增了屬性 dubbo.cloud.subscribed-services 的設置。而且該值爲服務提供方應用 "spring-cloud-dubbo-server-sample"。

  • dubbo.cloud.subscribed-services : 用於服務消費方訂閱服務提供方的應用名稱的列表,若需訂閱多應用,使用 "," 分割。

不推薦使用默認值爲 "*",它將訂閱全部應用。

當應用使用屬性 dubbo.cloud.subscribed-services 默認值時,日誌中將會輸出一行警告:

Current application will subscribe all services(size:x) in registry, a lot of memory and CPU cycles may be used,
thus it's strongly recommend you using the externalized property 'dubbo.cloud.subscribed-services' to specify the services

因爲當前應用屬於 Web 應用,它會默認地使用 8080 做爲 Web 服務端口,若是須要自定義,可經過屬性 server.port 調整。

以上完整的 YAML 配置文件,請參考 spring-cloud-dubbo-client-sample bootstrap.yaml 文件

引導 Dubbo Spring Cloud 服務消費方應用

爲了減小實現步驟,如下引導類將 Dubbo 服務消費以及引導功能合二爲一:

@EnableDiscoveryClient
@EnableAutoConfiguration
@RestController
public class DubboSpringCloudClientBootstrap {

    @Reference
    private EchoService echoService;

    @GetMapping("/echo")
    public String echo(String message) {
        return echoService.echo(message);
    }

    public static void main(String[] args) {
        SpringApplication.run(DubboSpringCloudClientBootstrap.class);
    }
}

不只如此,DubboSpringCloudClientBootstrap 也做爲 REST Endpoint,經過暴露 /echo Web 服務,消費 Dubbo EchoService 服務。所以,
可經過 curl 命令執行 HTTP GET 方法:

$ curl http://127.0.0.1:8080/echo?message=%E5%B0%8F%E9%A9%AC%E5%93%A5%EF%BC%88mercyblitz%EF%BC%89

HTTP 響應爲:

[echo] Hello, 小馬哥(mercyblitz)

以上結果說明應用 spring-cloud-dubbo-client-sample 經過消費 Dubbo 服務,返回服務提供方 spring-cloud-dubbo-server-sample 運算後的內容。

高階示例

若是您須要進一步瞭解 Dubbo Spring Cloud 使用細節,可參考官方 Samples:https://github.com/spring-clo...

其子模塊說明以下:

  • spring-cloud-dubbo-sample-api:API 模塊,存放 Dubbo 服務接口和模型定義
  • spring-cloud-dubbo-provider-web-sample:Dubbo Spring Cloud 服務提供方示例(Web 應用)
  • spring-cloud-dubbo-provider-sample:Dubbo Spring Cloud 服務提供方示例(非 Web 應用)
  • spring-cloud-dubbo-consumer-sample:Dubbo Spring Cloud 服務消費方示例
  • spring-cloud-dubbo-servlet-gateway-sample:Dubbo Spring Cloud Servlet 網關簡易實現示例

問題反饋

若是您在使用 Dubbo Spring Cloud 的過程當中遇到任何問題,請內容反饋至 https://github.com/spring-clo...

進階閱讀

關於更多的 Dubbo Spring Cloud 特性以及設計細節,請關注

下篇預告

接下的文章將會介紹 Dubbo Spring Cloud 高階示例的運用和實現,敬請關注小馬哥微信公衆號:次靈均閣

img

得到最新 Dubbo Spring Cloud 相關資訊。

新書推薦

本書全名爲《Spring Boot 編程思想》,是以 Spring Boot 2.0 爲討論的主線,討論的範圍將涵蓋 Spring Boot 1.x 的全部版本,以及所關聯的 Spring Framework 版本,致力於:

  • 場景分析:掌握技術選型
  • 系統學習:拒絕淺嘗輒止
  • 重視規範:瞭解發展趨勢
  • 源碼解讀:理解設計思想
  • 實戰演練:鞏固學習成果

clipboard.png

歡迎小夥伴在京東或噹噹訂購
京東存有少許現貨(隨機發送簽名版),可先睹爲快: http://t.cn/ExjBU2M
噹噹價格優惠,須要五月初發貨: http://t.cn/EX0QteF

分享推薦

免費分享

收費分享

深刻探討 Java 相關技術,包括行業動態,架構設計,設計模式,框架使用,源碼分析等。

關於做者

小馬哥,Java 勸退師,Apache 和 Spring Cloud 等知名開源架構成員,點擊查看詳情



  1. Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state). - https://spring.io/projects/sp...
  2. Apache Dubbo (incubating) |ˈdʌbəʊ| is a high-performance, light weight, java based RPC framework. - https://dubbo.apache.org
  3. Spring Cloud Alibaba provides a one-stop solution for distributed application development. - https://github.com/spring-clo...
  4. Nacos is an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications - https://nacos.io/
  5. Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers. - https://github.com/Netflix/eu...
  6. ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. - https://zookeeper.apache.org
  7. Consul is a distributed service mesh to connect, secure, and configure services across any runtime platform and public or private cloud - https://www.consul.io/
  8. Spring Cloud Open Feign - https://github.com/spring-clo...
  9. 從 2.7.0 開始,Dubbo Spring Boot 與 Dubbo 在版本上保持一致
  10. Preview releases of Spring Cloud Alibaba are available: 0.9.0, 0.2.2, and 0.1.2 - https://spring.io/blog/2019/0...
  11. 目前最新的 Spring Cloud 「F」 版的版本爲:Finchley.SR2 - https://cloud.spring.io/sprin...
  12. 當前Spring Cloud 「G」 版爲 Greenwich.RELEASE
  13. Spring Cloud 特性列表 - https://cloud.spring.io/sprin...
  14. Dubbo 2.7 開始支持配置中心,可自定義適配 - http://dubbo.apache.org/zh-cn...
  15. Spring Cloud 原生註冊中心,除 Eureka、Zookeeper、Consul 以外,還包括 Spring Cloud Alibaba 中的 Nacos
  16. Dubbo 原生註冊中心 - http://dubbo.apache.org/zh-cn...
  17. Alibaba Sentinel:Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性 - https://github.com/alibaba/Se...
  18. Spring Cloud Sleuth - https://spring.io/projects/sp...
  19. Zipkin - https://github.com/apache/inc...
相關文章
相關標籤/搜索