SOFABoot的哪些事:初探
前言
大家應(yīng)該都知道,最近我剛?cè)肼毿鹿荆杂泻枚鄸|西要去學(xué)習(xí),SOFABoot作為一個(gè)比較核心的框架,應(yīng)該是我后面技術(shù)攻堅(jiān)的重點(diǎn)對(duì)象,今天我們就先來簡(jiǎn)單了解下。
正文
SOFABoot是什么
SOFABoot 是螞蟻金服開源的基于 Spring Boot 的研發(fā)框架,它在 Spring Boot 的基礎(chǔ)上,提供了諸如 Readiness Check,類隔離,日志空間隔離等能力。在增強(qiáng)了 Spring Boot 的同時(shí),``SOFABoot提供了讓用戶可以在Spring Boot中非常方便地使用SOFA` 中間件的能力。
功能描述
SOFABoot 在 Spring Boot 基礎(chǔ)上,提供了以下能力:
擴(kuò)展 Spring Boot健康檢查的能力:在Spring Boot健康檢查能力基礎(chǔ)上,提供了Readiness Check的能力,保證應(yīng)用實(shí)例安全上線。提供模塊化開發(fā)的能力:基于 Spring上下文隔離提供模塊化開發(fā)能力,每個(gè)SOFABoot模塊使用獨(dú)立的Spring上下文,避免不同SOFABoot模塊間的BeanId沖突。增加模塊并行加載和 Spring Bean異步初始化能力,加速應(yīng)用啟動(dòng);增加日志空間隔離的能力:中間件框架自動(dòng)發(fā)現(xiàn)應(yīng)用的日志實(shí)現(xiàn)依賴并獨(dú)立打印日志,避免中間件和應(yīng)用日志實(shí)現(xiàn)綁定,通過 sofa-common-tools實(shí)現(xiàn)。增加類隔離的能力:基于 SOFAArk框架提供類隔離能力,方便使用者解決各種類沖突問題。增加中間件集成管理的能力:統(tǒng)一管控、提供中間件統(tǒng)一易用的編程接口、每一個(gè) SOFA中間件都是獨(dú)立可插拔的組件。提供完全兼容 Spring Boot的能力:``SOFABoot基于Spring Boot的基礎(chǔ)上進(jìn)行構(gòu)建,并且完全兼容Spring Boot`。
應(yīng)用場(chǎng)景
SOFABoot 本身就脫胎于螞蟻金服內(nèi)部對(duì)于 Spring Boot 的實(shí)踐,補(bǔ)充了 Spring Boot 在大規(guī)模金融級(jí)生產(chǎn)場(chǎng)景下一些不足的地方,所以 SOFABoot 特別適合于這樣的場(chǎng)景。
當(dāng)然,SOFABoot 的每個(gè)組件都是可選的,用戶可以靈活選擇其中的功能來使用,比如如果僅僅想在 Spring Boot 下面引入 SOFA 中間件,可以不需引入 SOFABoot 中的類隔離能力。
簡(jiǎn)單示例
接下來我們簡(jiǎn)單看下如何用SOFABoot構(gòu)建我們的項(xiàng)目,這里我們直接構(gòu)建rpc項(xiàng)目。SOFABoor本身就是一個(gè)比較強(qiáng)大,但是也比較復(fù)雜的框架,所以為了能夠嚼爛它,我們先挑軟的來。
下面是SOFARPC的架構(gòu)圖:

創(chuàng)建項(xiàng)目
這里我們創(chuàng)建一個(gè)spring boot項(xiàng)目,這里我們只需要引入starter-web即可:

創(chuàng)建完成后pom文件的依賴如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.syske</groupId>
<artifactId>sofaboot-rpc-demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sofaboot-rpc-demo2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>io.github.syske.sofabootrpcdemo2.SofabootRpcDemo2Application</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
修改依賴
首先我們要增加parent節(jié)點(diǎn),節(jié)點(diǎn)配置的是sofaboot-dependencies:
<parent>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofaboot-dependencies</artifactId>
<version>3.1.0</version>
</parent>
然后增加rpc-sofa的依賴
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>rpc-sofa-boot-starter</artifactId>
</dependency>
創(chuàng)建facade接口
facade就是rest接口中的service
/**
* @program: sofaboot-rpc-demo2
* @description: hello
* @author: syske
* @create: 2021-04-11 10:55
*/
public interface HelloService {
String sayHello(String name);
}
創(chuàng)建服務(wù)提供者
/**
* @program: sofaboot-rpc-demo2
* @description: hello服務(wù)實(shí)現(xiàn)類
* @author: syske
* @create: 2021-04-11 10:59
*/
@SofaService(interfaceType = HelloService.class, bindings = { @SofaServiceBinding(bindingType = "bolt") })
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return name + ", hello!";
}
}
SofaService的作用是注冊(cè)sofa服務(wù),其中SofaServiceBinding的作用是指定服務(wù)注冊(cè)協(xié)議,目前支持 bolt,RESTful,dubbo,H2C,jvm,不指定的話,默認(rèn)就是jvm,其中 bolt 是螞蟻金融服務(wù)集團(tuán)開放的基于 Netty 開發(fā)的網(wǎng)絡(luò)通信框架。這里我們用的也是bolt。
添加注冊(cè)中心配置
根據(jù)SOFARPC架構(gòu)圖,我們知道SOFARPC是需要注冊(cè)中心的,所以這里我們指定zookeeper作為注冊(cè)中心:
com.alipay.sofa.rpc.registry.address=zookeeper://127.0.0.1:2181
當(dāng)然SOFABoot也支持其他注冊(cè)中心,比如nocas
啟動(dòng)
項(xiàng)目本身就是基于spring boot項(xiàng)目,所以啟動(dòng)方法與啟動(dòng)spring boot項(xiàng)目一樣。
依賴報(bào)錯(cuò)
如果啟動(dòng)報(bào)如下錯(cuò)誤:
***************************
APPLICATION FAILED TO START
***************************
Description:
An attempt was made to call the method org.springframework.core.type.AnnotationMetadata.introspect(Ljava/lang/Class;)Lorg/springframework/core/type/AnnotationMetadata; but it does not exist. Its class, org.springframework.core.type.AnnotationMetadata, is available from the following locations:
jar:file:/E:/TheServer/repository/org/springframework/spring-core/5.1.2.RELEASE/spring-core-5.1.2.RELEASE.jar!/org/springframework/core/type/AnnotationMetadata.class
It was loaded from the following location:
file:/E:/TheServer/repository/org/springframework/spring-core/5.1.2.RELEASE/spring-core-5.1.2.RELEASE.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of org.springframework.core.type.AnnotationMetadata
請(qǐng)刪除pom中的如下配置后重新啟動(dòng):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
導(dǎo)致找個(gè)錯(cuò)誤的原因是重復(fù)依賴,初步推測(cè)可能是因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">SOFABoot已經(jīng)包含了該依賴,再次依賴就會(huì)報(bào)錯(cuò)。
注冊(cè)中心報(bào)錯(cuò)
因?yàn)楸卷?xiàng)目依賴注冊(cè)中心,所以在啟動(dòng)項(xiàng)目前請(qǐng)先啟動(dòng)注冊(cè)中心,否則會(huì)報(bào)如下錯(cuò)誤:
2021-04-11 11:33:09.640 WARN 6096 --- [127.0.0.1:2181)] org.apache.zookeeper.ClientCnxn : Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused: no further information
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[na:1.8.0_251]
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717) ~[na:1.8.0_251]
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361) ~[zookeeper-3.4.6.jar:3.4.6-1569965]
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1081) ~[zookeeper-3.4.6.jar:3.4.6-1569965]
查詢服務(wù)是否注冊(cè)成功
啟動(dòng)成功后,我們通過zkCli連接zookeeper確認(rèn)服務(wù)是否注冊(cè)成功:
$ ls /sofa-rpc
$ ls /sofa-rpc/io.github.syske.sofabootrpcdemo2.facade.HelloService/providers
如果注冊(cè)成功,顯示結(jié)果應(yīng)該是這樣的:

如果還有小伙伴不知道如何使用zookeeper可以私信我。
測(cè)試
這里我偷個(gè)懶就不寫服務(wù)消費(fèi)者了,直接在測(cè)試用例中調(diào)用,為了能在zookeeper中查看服務(wù)消費(fèi)者,我這里加了一些循環(huán):
@SpringBootTest
class SofabootRpcDemo2ApplicationTests {
@Test
void contextLoads() {
int i = 0;
long start = System.currentTimeMillis();
while(i < 10000) {
System.out.println(sayClientAnnotation("test"));
i++;
}
long stop = System.currentTimeMillis();
System.out.println("用時(shí):" + (stop - start));
}
@SofaReference(interfaceType = HelloService.class, binding = @SofaReferenceBinding(bindingType = "bolt"))
private HelloService helloService;
public String sayClientAnnotation(String str) {
String result = helloService.sayHello(str);
return result;
}
}
這里需要解釋的是SofaReference的作用是發(fā)現(xiàn)服務(wù),一般就是遠(yuǎn)程調(diào)用的時(shí)候發(fā)現(xiàn)服務(wù)的,它和SofaService是對(duì)應(yīng)的,注冊(cè)的服務(wù)和調(diào)用的服務(wù)必須一致才能正常調(diào)用成功。
結(jié)語(yǔ)
其實(shí),目前我對(duì)SOFABoot的認(rèn)知還比較淺顯,后面還需要進(jìn)一步的探索和研究,當(dāng)然同步增強(qiáng)的還有RPC相關(guān)的知識(shí)點(diǎn),后面我想先去了解下restful和rpc協(xié)議的區(qū)別,目前我就知道相比于restful協(xié)議(三次握手)rpc效率更高,響應(yīng)速度更快,所以這塊的知識(shí)點(diǎn)還需要進(jìn)一步加強(qiáng),然后再深入了解SOFABoot、Spring boot相關(guān)內(nèi)容,從源碼層面更深入認(rèn)識(shí)他們,當(dāng)然與之相關(guān)的組件也在我們后續(xù)研究學(xué)習(xí)的范疇之中。好了,今天就先到這里吧,小伙伴們周末愉快呀!??????
示例代碼獲取還是老地方:
https://github.com/Syske/learning-dome-code
- END -