1. 程式人生 > >螞蟻金服開源 ——基於 SOFABoot 進行模組化開發

螞蟻金服開源 ——基於 SOFABoot 進行模組化開發

SOFA 中介軟體是螞蟻金服自主研發的金融級分散式中介軟體,包含了構建金融級雲原生架構所需的各個元件,包括微服務研發框架,RPC 框架,服務註冊中心,分散式定時任務,限流/熔斷框架,動態配置推送,分散式鏈路追蹤,Metrics監控度量,分散式高可用訊息佇列,分散式事務框架,分散式資料庫代理層等元件,是在金融場景裡錘鍊出來的最佳實踐。

SOFABoot 是螞蟻金服中介軟體團隊開源的基於 Spring Boot 的一個開發框架,SOFABoot 從 2.4.0 版本開始支援基於 Spring 上下文隔離的模組化開發能力,SOFABoot 模組除了包括 Java 程式碼外,還會包含 Spring 配置檔案,每個 SOFABoot 模組都是獨立的 Spring 上下文。

SOFABoot 的 Github 的地址是:

https://github.com/alipay/sofa-boot 

  背景

為了更好的理解 SOFABoot 模組化開發的概念,我們來區分幾個常見的模組化形式:

  • 基於程式碼組織上的模組化:這是最常見的形式,在開發期,將不同功能的程式碼放在不同 Java 工程下,在編譯期被打進不同 jar 包,在執行期,所有 Java 類都在一個 classpath 下且使用同一個 Spring 上下文,沒做任何隔離;

  • 基於 Spring 上下文隔離的模組化:使用 Spring 上下文來做不同功能模組的隔離,在開發期和編譯期,程式碼和配置也會分在不同 Java 工程中,但在執行期,不同的 Spring Bean 相互不可見,IoC 只在同一個上下文內部發生,但是所有的 Java 類還是在一個 ClassLoader 下;

  • 基於 ClassLoader 隔離的模組化:借用 ClassLoader 來做隔離,每個模組都有獨立的 ClassLoader,模組與模組之間的 classpath 不同,SOFAArk 就是這種模組化的實踐方式。

以上三種模組化形式的隔離化程度逐次遞進,但模組化就像一把雙刃劍,在降低模組間耦合的同時也給模組間互動增加了成本

本文介紹第二種模組化形式 — 基於 Spring 上下文隔離的模組化。

與基於程式碼組織上的模組化相比,每個 SOFABoot 模組不僅僅包括 Java 程式碼,還會包含 Spring 配置檔案,這種全新的包組織方式大大降低了使用者接入成本,使用者只需要簡單的引入 Jar 包即可,由 SOFABoot 框架負責重新整理模組上下文,無需在原來 Spring 配置檔案中新增任何 Bean 定義,簡化了接入流程,降低了出錯機率。

每個 SOFABoot 模組的 Spring 上下文都是隔離的。在 Spring 開發中,保證 Spring BeanId 不衝突是 Spring 執行的基礎,這個限制在應用規模較小時很容易解決,只需使用者在定義 BeanId 時稍加註意即可。

但是隨著系統規模越來越大,一個系統的開發往往涉及多個團隊,保證每個業務定義 BeanId 不重複的成本也越來越高。在 SOFABoot 中,每個 SOFABoot 模組使用獨立的 Spring 上下文,避免了不同 SOFABoot 模組間 BeanId 衝突,有效降低企業級多模組開發時團隊間的溝通成本。

  基本原理

在介紹 SOFABoot 模組化開發使用之前,我們簡單瞭解下其背後的實現原理。下圖是應用執行時的邏輯檢視:

SOFABoot 模組是模組化開發的最小單元,每個 SOFABoot 模組是一個獨立的 Spring 上下文,在 SOFABoot 模組中我們可以定義Bean、釋出 RPC 服務、連線資料庫等等。

由於上下文隔離,模組與模組之間的 Bean 無法通過 @Autowired 依賴注入,我們提供了 JVM Service/Reference 的方式進行模組間通訊。

SOFABoot 提供了兩種形式的服務釋出和引用,用於解決不同級別的模組間呼叫問題:

  • JVM 服務釋出和引用:解決一個 SOFABoot 應用內部各個 SOFABoot 模組之間的呼叫問題

  • RPC 服務釋出和引用:解決多個 SOFABoot 應用之間的遠端呼叫問題

Spring Boot 應用在呼叫 SpringApplication.run 時會建立一個 Spring Context,我們把它叫做 Root Application Context,它是每個 SOFABoot 模組建立的 Spring Context 的 Parent。這樣設計的目的是為了保證每個 SOFABoot 模組的 Spring Context 都能發現 Root Application Context 中建立的 Bean,這樣當應用新增 Starter 時,不僅 Root Application Context 能夠使用 Starter 中新增的 Bean,每個 SOFABoot 模組的 Spring Context 也能使用這些 Bean。

下面我們來演示如何開發一個簡單的 SOFABoot 模組

1 新建工程

DEMO 工程地址:

https://github.com/caojie09/sofaboot-module-demo

執行需要 JDK 6 及以上、 Maven 3.2.5 以上。

首先我們在 IDE 裡新建一個普通 Maven 工程,並建立兩個普通的 Maven 模組:

  • service-facade: 定義服務介面

  • service-provide: 演示新建 SOFABoot 模組併發布 JVM 服務

2. 定義服務介面

service-facade 模組包含用於演示 SOFABoot 模組釋出與引用服務介面:

public interface SampleService {    String message();
}

3. 定義 SOFABoot 模組

service-provider 是一個 SOFABoot 模組,它會發佈一個 JVM 服務供其他模組使用。首先需要為 service-provider 模組增加 sofa-module.properties 檔案,將其定義為 SOFABoot 模組,sofa-module.properties 檔案放置在 resources 目錄:

Module-Name=com.alipay.sofa.service-provider

4. 釋出服務

SOFABoot 支援三種形式的服務釋出,分別是: XML 方式、Annotation 方式以及 API 編碼方式,這裡演示的是 XML 方式釋出服務。

首先增加 SampleServiceImpl 類,實現 SampleService 介面:

public class SampleServiceImpl implements SampleService {  

 private String message;    public String message() {  

     return message;    

}    

public String getMessage() {      

 return message;    

}    

public void setMessage(String message) {

       this.message = message;    

}
}

增加 META-INF/spring/service-provide.xml 檔案,將 SampleServiceImpl 釋出為 JVM 服務:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:sofa="http://sofastack.io/schema/sofaboot"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd            http://sofastack.io/schema/sofaboot http://sofastack.io/schema/sofaboot.xsd"       default-autowire="byName">    <bean id="sampleService" class="com.alipay.sofa.isle.sample.SampleServiceImpl">        <property name="message" value="Hello, SOFABoot module."/>    </bean>    <sofa:service ref="sampleService" interface="com.alipay.sofa.isle.sample.SampleService">        <sofa:binding.jvm/>    </sofa:service>
</beans>

到此為止,我們就成功新建了一個 SOFABoot 模組,並在模組中釋出了一個 JVM 服務,可以看到,一個 SOFABoot 模組不僅僅包括程式碼,還包括 Spring 配置檔案。

接下來,在 Spring Boot 工程中,快速整合 SOFABoot 的模組化開發能力,並使用剛剛新建的模組釋出的服務

Spring Boot 工程整合模組化開發元件

1. 新建工程

Demo 工程地址:

https://github.com/caojie09/sofaboot-module-run

在 Spring Boot 官網 https://start.spring.io 新建一個 web 工程,請選擇 Spring Boot 版本號為 1.X,目前不支援 Spring Boot 2。修改 maven 專案的配置檔案 pom.xml,

<parent>  

 <groupId>org.springframework.boot</groupId>  

 <artifactId>spring-boot-starter-parent</artifactId>  

 <version>1.5.14.RELEASE</version>  

 <relativePath/>
</parent>

替換為:

<parent>    

<groupId>com.alipay.sofa</groupId>  

 <artifactId>sofaboot-dependencies</artifactId>  

 <version>2.4.2</version>
</parent>

並新增如下依賴:
 

<dependency>    

<groupId>com.alipay.sofa</groupId>    

<artifactId>isle-sofa-boot-starter</artifactId>
</dependency>

這樣,一個 Spring Boot 工程便集成了 SOFABoot 模組化開發能力。

2. 新增 SOFABoot 模組

新增 SOFABoot 模組很簡單,只需要把 SOFABoot 模組的座標加在當前 maven 工程即可,對於這個例子,只需要在啟動類模組新增上面建立的 service-provider 模組:

<dependency>    

<groupId>com.alipay.sofa</groupId>    

<artifactId>service-provide</artifactId>    

<version>1.0.0</version>
</dependency>

與傳統的 JAR 包程式碼分發方式相比,SOFABoot 模組不僅僅包括程式碼,還包括 Spring 配置檔案,使用者在使用 SOFABoot 模組時,只需增加依賴即可。

3. 引用服務

為了直觀演示,我們在演示工程增加了一個 Rest 介面,在 Rest 介面中引用上文 SOFABoot 模組釋出的 JVM 服務。這裡演示的是 Annotation 方式引用服務,只需在類的欄位上增加 @SofaReference 註解即可:

@RestController
public class HelloController {    

@SofaReference    private SampleService sampleService;    

@RequestMapping("/hello-sofamodule")    

public String hello() throws IOException {        

return sampleService.message();    

}
}

訪問 http://localhost:8080/hello-sofamodule,可以看到 HelloController 成功呼叫到了 service-provider 釋出的服務。

  總結

本文主要介紹了使用 SOFABoot 進行上下文隔離的模組化開發,通過兩個簡單的用例工程,分別介紹瞭如何開發一個 SOFABoot 模組以及如何在 Spring Boot 快速整合模組化開發能力。每個 SOFABoot 模組都是獨立的 Spring 上下文,SOFABoot 模組不僅僅包括程式碼,還包括 Spring 配置檔案,使用者在引用 SOFABoot 模組時,只需簡單增加依賴即可,由框架負責重新整理模組上下文,無需在 Spring 中新增任何 Bean 定義,簡化了接入流程,降低了出錯機率。