企業級SpringBoot與Dubbo的並用
SpringBoot越來越熱門以至於達到爛大街可見的程度,而Dubbo這個基於二進位制的微服務框架又捐獻給Apache孵化,如果不會如何使用那麼是不是很不好意思呢?
這次從公司的專案中抽一個小列子來熟悉下如果從零構建,至於深入瞭解->傳送門:Dubbo官方中文手冊
版本:
- Springboot2.x
- Double2.6
- Zk3.4.14
- JDK8
這裡就不介紹Dubbo了,傳送去看看以前的:網際網路級微服務架構神器Duubo
zookeepr安裝
下載去官網查詢穩定的版本進行使用:http://www.apache.org/dyn/closer.cgi/zookeeper/
先在伺服器上安裝zookeeper。
cd /usr/local/src/
#下載
sudo wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
#解壓
tar -zxvf zookeeper-3.4.14.tar.gz
#修改配置檔名稱
mv conf/zoo_sample.cfg zoo.cfg
#啟動zk
./bin/zkServer.sh start
#出現以下字樣代表啟動成功,預設埠2181
Starting zookeeper ... STARTED
SpringBoot2.x整合Dubbo
父工程搭建(pom工程)
<groupId>com.simple.springboot</groupId>
<artifactId>yun-double</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>yun-double</name>
<description>double</description>
<!--統一管理依賴版本-->
<properties>
<java.version>1.8</java.version>
<double.version>2.0.0</double.version>
<zkclient.version>0.10</zkclient.version>
</properties>
<!-- 依賴於SpringBoot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/>
</parent>
<!--依賴定義-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${double.version}</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>${zkclient.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
建立公共介面工程common
該工程用於儲存服務層介面,以減少程式碼的冗餘。
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.simple.springboot</groupId>
<artifactId>yun-double</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.simple.springboot</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>common</name>
<description>公共介面</description>
建立公共介面
public interface UserService {
String getUserById(int id);
}
建立服務提供者(provider)
Pom檔案
<modelVersion>4.0.0</modelVersion>
<groupId>com.simple.springboot</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>provider</name>
<description>生產者</description>
<parent>
<groupId>com.simple.springboot</groupId>
<artifactId>yun-double</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<!-- SpringBoot快速啟動Duubbo -->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- Zk客戶端依賴 -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<!-- 排除依賴裡的日誌 -->
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 匯入公共介面依賴 -->
<dependency>
<groupId>com.simple.springboot</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
在pom檔案中我們需要引入Dubbo,Zk客戶端並且引入公共介面工程
application.properties配置檔案
#dubbo.application.name 應用名稱
#dubbo.registry.address 註冊中心地址
#dubbo.protocol.name 協議名稱
#dubbo.protocol.port 協議埠
#dubbo.scan dubbo 服務類包目錄
#server.port=8080
spring.application.name=user-pro
dubbo.application.name=user-provider1
dubbo.registry.address=zookeeper://192.168.197.133:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
在這裡dubbo.application.name應用名稱一定不能重複
實現UserService
@Component
@Service(timeout = 10000,interfaceClass = UserService.class)
public class UserServiceImpl implements UserService {
@Override
public String getUserById(int id) {
if(id == 1) {
return "SimpleWu";
}else {
return "Apache Dubbo";
}
}
}
@Service 這個註解使用的不是Spring裡面的而是com.alibaba.dubbo.config.annotation.Service
timeout 配置超時時間
interfaceClass 介面類
version 服務版本,如果配置了服務版本在消費端引用也必須一樣,具體等會說
建立啟動類
在該工程中我們不需要引入Web模組浪費埠號,只需要這樣寫啟動類
@EnableDubbo
@EnableDubboConfiguration
@DubboComponentScan("com.simple.springboot.provider.common.impl")
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(ProviderApplication.class);
app.run(args);
//dubbo Main獨立執行,脫離web容器
Main.main(args);
}
}
@EnableDubbo 啟動Dubbo功能
@EnableDubboConfiguration 啟動Duubbo配置
@DubboComponentScan 掃描提供者實現類
建立服務消費者(consumer)
POM檔案
<modelVersion>4.0.0</modelVersion>
<groupId>com.simple.springboot</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer</name>
<description>消費者</description>
<parent>
<groupId>com.simple.springboot</groupId>
<artifactId>yun-double</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<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>
</dependency>
<!-- SpringBoot快速啟動Duubbo -->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- Zk客戶端依賴 -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<!-- 排除依賴裡的日誌 -->
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 匯入公共介面依賴 -->
<dependency>
<groupId>com.simple.springboot</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
在這個工程中我們是需要依賴Web的,不然咋訪問呢
編寫Application.properties配置檔案
spring.application.name=user-con
server.port=8080
dubbo.application.name=user-consumer
dubbo.registry.address=zookeeper://192.168.197.133:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
#dubbo.scan=com.simple.springboot.provider.common.impl
在這裡dubbo.application.name應用名稱一定不能重複
dubbo.scan 該配置指向應該是要和服務提供方一致
編寫Controller
@RestController
public class UserController {
//timeout 可以不指定,如果提供則有填寫但是version一定要指定 不然會找不到服務 直連需要加url="dubbo://localhost:20880"
@Reference
private UserService userService;
@GetMapping("/dubbo/user/{id}")
public String getUserById(@PathVariable int id){
return userService.getUserById(id);
}
}
在這裡是使用@Reference去發現服務而不是@Autowired去注入Bean
@Reference 裡面可以配置version,timeout超時時間
如果需要Dubbo直連url="dubbo://localhost:20880"
dubbo提供了四種負載均衡策略,分別是:
1、Random LoadBalance 按權重的隨機負載均衡,也是dubbo預設的負載均衡策略
2、RoundRobin LoadBalance 按權重的輪詢負載均衡,即在輪詢的基礎上新增了權重的策略
3、LeastActive LoadBalance 最少活躍呼叫數,相同活躍數的隨機訪問,活躍數指呼叫前後的計數差即響應時間的長短;這種策略可以使響應慢的提供者收到的請求較少,大大提供系統效能
4、ConsistentHash LoadBalance 一致性雜湊;相同引數的請求總是發到同一提供者
負載均衡的配置:@Reference(loadbalance = "roundrobin"),loadbalance 的值即為四種負載均衡的名稱,全部小寫
在叢集呼叫失敗時,Dubbo 提供了多種容錯方案,預設為 failover 重試。下面列舉dubbo支援的容錯策略:
1、Failover Cluster:失敗自動切換,當出現失敗,重試其它伺服器。通常用於讀操作,但重試會帶來更長延遲。可通過 retries="XXX" 來設定重試次數(不含第一次)。
2、Failfast Cluster:快速失敗,只發起一次呼叫,失敗立即報錯。通常用於非冪等性的寫操作,比如新增記錄。
3、Failsafe Cluster:失敗安全,出現異常時,直接忽略。通常用於寫入審計日誌等操作。
4、Failback Cluster:失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於訊息通知操作。
5、Forking Cluster:並行呼叫多個伺服器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks="2" 來設定最大並行數。
6、Broadcast Cluster:廣播呼叫所有提供者,逐個呼叫,任意一臺報錯則報錯 [2]。通常用於通知所有提供者更新快取或日誌等本地資源資訊。
配置如下:@Reference(cluster = "failsafe")這裡表示使用失敗安全的容錯策略
編寫啟動類
/**
* @author:SimpleWu
* @date: 2019-05-08
*/
@EnableDubbo
@SpringBootApplication
@EnableDubboConfiguration
@DubboComponentScan("com.simple.springboot.provider.common.impl")
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
然後直接就可以訪問成功了。
如果不想使用註解掃描可以使用properties進行配置
#dubbo.scan=com.simple.springboot.provider.common.impl
參考程式碼:傳送門
注意事項:
Dubbo是一個二進位制的Rpc框架在傳輸資料過程中,實體類必須經過序列化。
在使用poi匯出功能時一定不能把response傳到Service層,否則傳輸到Service是匯出不了檔案而報錯,至於檔案下載也一樣但是相信一般都會有單獨的檔案伺服器。