SpringBoot系列之集成Dubbo示例教程
一、分布式基本理論
1.1、分布式基本定義
《分布式系統(tǒng)原理與范型》定義:
“分布式系統(tǒng)是若干獨立計算機的集合,這些計算機對于用戶來說就像單個相關(guān)系統(tǒng)”
分布式系統(tǒng)(distributed system)是建立在網(wǎng)絡(luò)之上的軟件系統(tǒng)。
1.2 架構(gòu)發(fā)展演變
架構(gòu)的發(fā)展是由最初的單一應(yīng)用架構(gòu)構(gòu)建的,一般就是ORM框架方便數(shù)據(jù)庫操作。
不過隨著系統(tǒng)越來越復(fù)雜,單一應(yīng)用架構(gòu)會變得難以維護,所以架構(gòu)逐漸演變出了垂直應(yīng)用架構(gòu),所謂垂直應(yīng)用架構(gòu)其實就是安裝業(yè)務(wù)模板進行拆分,比如可以安裝業(yè)務(wù)將一個電商系統(tǒng)分為訂單模塊,用戶信息管理模塊,商品管理模塊等等,這時候MVC框架就派上用場,MVC框架可以協(xié)助系統(tǒng)更好的按業(yè)務(wù)拆分,不過業(yè)務(wù)拆分后雖然是比單一應(yīng)用架構(gòu)更好維護了。
不過隨著系統(tǒng)越來約復(fù)雜,發(fā)現(xiàn)很多共用的模塊很難復(fù)用起來,這時候分布式服務(wù)架構(gòu)登場了,分布式架構(gòu)是將一些核心業(yè)務(wù)抽取出來,作為獨立的服務(wù),逐漸形成穩(wěn)定的服務(wù)中心,當(dāng)應(yīng)用需要時,就去服務(wù)中心調(diào)服務(wù)就可以,而實現(xiàn)這種服務(wù)注冊的肯定是RPC框架了。
當(dāng)服務(wù)越來越多,容量的評估,小服務(wù)資源的浪費等問題逐漸顯現(xiàn),此時需增加一個調(diào)度中心基于訪問壓力實時管理集群容量,提高集群利用率,這時候就需要流動計算架構(gòu)(SOA)[ Service Oriented Architecture],用于提高機器利用率的資源調(diào)度,SOA是一個治理中心,綜上所述,到目前,軟件系統(tǒng)架構(gòu)演變經(jīng)歷了:單一應(yīng)用架構(gòu)->垂直應(yīng)用架構(gòu)->分布式應(yīng)用架構(gòu)->流動計算架構(gòu),下面Dubbo官網(wǎng)的圖片可以很好的描述
1.3、RPC簡介
RPC概念
RPC【Remote Procedure Call】是指遠程過程調(diào)用,是一種進程間通信方式,他是一種技術(shù)的思想,而不是規(guī)范。它允許程序調(diào)用另一個地址空間(通常是共享網(wǎng)絡(luò)的另一臺機器上)的過程或函數(shù),而不用程序員顯式編碼這個遠程調(diào)用的細節(jié)。
RPC核心模塊
RPC有兩個核心模塊:通信和序列化
二、Dubbo理論簡介
Apache Dubbo (incubating) |?d?b??| 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調(diào)用,智能容錯和負載均衡,以及服務(wù)自動注冊和發(fā)現(xiàn)。
官網(wǎng):
http://dubbo.apache.org/

Dubbo的服務(wù)治理:
Dubbo原理圖片,圖片來自Dubbo官網(wǎng):

Dubbo角色:
Provider:暴露服務(wù)的服務(wù)提供者
Container:服務(wù)運行的容器
Consumer:調(diào)用遠程服務(wù)的消費者
Registry:服務(wù)注冊和發(fā)現(xiàn)的注冊中心
Minitor:統(tǒng)計服務(wù)調(diào)用次數(shù)和時間的監(jiān)控中心
調(diào)用過程:
下面根據(jù)我的理解說明一下
0:服務(wù)器容器負責(zé)啟動、加載、運行服務(wù)提供者
1:服務(wù)提供者在啟動后就可以向注冊中心暴露服務(wù)
2:服務(wù)消費者在啟動后就可以向注冊中心訂閱想要的服務(wù)
3:注冊中心向服務(wù)消費者返回服務(wù)調(diào)用列表
4:服務(wù)消費者基于軟負載均衡算法調(diào)用服務(wù)提供者的服務(wù),這個服務(wù)提供者有可能是一個服務(wù)提供者列表,調(diào)用那個服務(wù)提供者就是根據(jù)負載均衡來調(diào)用了
5:服務(wù)提供者和服務(wù)消費者定時將保存在內(nèi)存中的服務(wù)調(diào)用次數(shù)和服務(wù)調(diào)用時間推送給監(jiān)控中心
三、Dubbo環(huán)境搭建
3.1 Zookeeper搭建
搭建Zookeeper,首先是搭建分布式架構(gòu)的注冊中心Zookeeper,當(dāng)然也可以用Redis等等來做服務(wù)注冊中心,不過本博客只介紹Zookeeper的,因為沒有l(wèi)inux服務(wù)器,所以只介紹window版的搭建
1、下載Zookeeper:
網(wǎng)址?https://archive.apache.org/dist/zookeeper/zookeeper-3.4.13/2、解壓Zookeeper
解壓Zookeeper之后,運行bin目錄里的zkServer.cmd,發(fā)現(xiàn)報錯了,提示找不到配置文件,所以需要繼續(xù)步驟33、配置Zookeeper
因為Zookeeper的conf文件夾下面只提供zoo_sample.cfg文件,需要自己修改命名為zoo.cfg
對于配置文件需要注意:
dataDir=./ 臨時數(shù)據(jù)存儲的目錄(可寫相對路徑)
clientPort=2181 zookeeper的端口號
4、使用zkCli.cmd測試
修改配置文件后,重新啟動zkServer.cmd,啟動bin目錄下面的zkCli.cmd,很顯然這是個客戶端程序,注意zkServer.cmd是服務(wù)端程序,必須啟動
ok,簡單在zkCli.cmd敲幾個命令測試一下:
ls /:列出zookeeper根下保存的所有節(jié)點
create –e /testNode 12345678:創(chuàng)建一個testNode節(jié)點,值為12345678
get /testNode:獲取/testNode節(jié)點的值
3.2 Dubbo管理頁面搭建
搭建了服務(wù)注冊中心后,就需要搭建Dubbo-admin了,最近看了一下,dubbo的Github項目已經(jīng)進行了更新,管理平臺已經(jīng)做了比較大的改動,而我學(xué)習(xí)的時候,平臺是比較簡單的,所以本dubbo-admin搭建是以舊版master的為準(zhǔn),不過以學(xué)習(xí)為目的的,只需要知道具體原理和操作技巧就可以
下載dubbo-admin
去下載一下dubbo-admin,可以找主干master分支的,找到dubbo-admin,git clone到本地
https://github.com/apache/incubator-dubbo-ops
因為我搭建時候(ps:不是博客寫作時間),dubbo還沒做比較大改動,所以我以比較舊的版本為例子,現(xiàn)在新的具體參考dubbo官方的教程,本博客只是做記錄
修改dubbo-admin
修改 src\main\resources\application.properties 指定zookeeper地址
Maven package dubbo-admin
mvn clean package -Dmaven.test.skip=true
運行dubbo-admin的jar
maven打包之后,就去target里找到j(luò)ar,然后cmd運行
java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
運行成功之后,訪問:?http://127.0.0.1:7001,輸入默認(rèn)的賬號密碼root/root,登錄成功

四、Dubbo服務(wù)注冊發(fā)現(xiàn)例子
經(jīng)典例子(引用尚硅谷教程例子進行改寫):
4.1、業(yè)務(wù)場景
某個電商系統(tǒng),訂單服務(wù)需要調(diào)用用戶服務(wù)獲取某個用戶的所有地址;
我們現(xiàn)在 需要創(chuàng)建兩個服務(wù)模塊進行測試
| 模塊 | 功能 |
|---|---|
| 訂單服務(wù)模塊 | 創(chuàng)建訂單等 |
| 用戶服務(wù)模塊 | 查詢用戶地址等 |
測試預(yù)期結(jié)果:
訂單服務(wù)web模塊在A服務(wù)器,用戶服務(wù)模塊在B服務(wù)器,A可以遠程調(diào)用B的功能
4.2、api工程創(chuàng)建
創(chuàng)建工程:
建議將服務(wù)接口,服務(wù)模型,服務(wù)異常等均放在 API 包中,因為服務(wù)模型及異常也是 API 的一部分,同時,這樣做也符合分包原則:重用發(fā)布等價原則(REP),共同重用原則(CRP)。
創(chuàng)建一個API工程,將實體類和接口都放在api工程
maven新建一個shop-api-common工程:
用戶地址DTO類:
package com.test.dubbo.bean;
import java.io.Serializable;
public class UserAddress implements Serializable {
private Integer id;
private String userAddress; //用戶地址
private String userId; //用戶id
private String consignee; //收貨人
private String phoneNum; //電話號碼
private String isDefault; //是否為默認(rèn)地址 Y-是 N-否
public UserAddress() {
super();
}
public UserAddress(Integer id, String userAddress, String userId, String consignee, String phoneNum,
String isDefault) {
super();
this.id = id;
this.userAddress = userAddress;
this.userId = userId;
this.consignee = consignee;
this.phoneNum = phoneNum;
this.isDefault = isDefault;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getConsignee() {
return consignee;
}
public void setConsignee(String consignee) {
this.consignee = consignee;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public String getIsDefault() {
return isDefault;
}
public void setIsDefault(String isDefault) {
this.isDefault = isDefault;
}
}
用戶信息服務(wù)接口:
package com.test.dubbo.service;
import java.util.List;
import com.test.dubbo.bean.UserAddress;
/**
* 用戶服務(wù)
*/
public interface UserService {
/**
* 按照用戶id返回所有的收貨地址
* @param userId
* @return
*/
public List getUserAddressList(String userId);
}
訂單信息服務(wù)接口:
package com.test.dubbo.service;
import java.util.List;
import com.test.dubbo.bean.UserAddress;
public interface OrderService {
/**
* 初始化訂單
* @param userId
*/
public List initOrder(String userId);
}
ok,創(chuàng)建好api工程
4.3、服務(wù)提供者工程
要實現(xiàn)服務(wù)提供,配置文件主要需要配置如下:
Dubbo提供者加載過程(Dubbo容器的啟動):
Spring加載xml配置之后暴露服務(wù)的過程:
Exporter方法主要是打開socket的監(jiān)聽,接收客戶的請求
ok,理解了上面的理論知識后,繼續(xù)創(chuàng)建一個user-service-provider工程:
參考Dubbo官方例子
2.2.1.RELEASE
2.7.5
2.12.0
org.apache.dubbo
dubbo-spring-boot-starter
${dubbo.version}
org.apache.dubbo
dubbo-dependencies-zookeeper
${dubbo.version}
pom
org.slf4j
slf4j-log4j12
我用的Springboot版本是2.2.1,dubbo starter版本是2.7.5,啟動之后,發(fā)現(xiàn)報錯
Caused by: java.lang.: org.apache.curClassNotFoundExceptionator.framework.CuratorFrame
找不到對應(yīng)的類,看起來是缺少jar了?通過網(wǎng)上資料搜索再加上如下配置即可:
org.apache.curator
curator-framework
${curator.version}
org.apache.curator
curator-recipes
${curator.version}
curator是Zookeeper配置需要的
maven配置好之后,就可以進行dubbo配置:
#server.port=7010
dubbo.application.name=user-service-provider
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20882
dubbo.monitor.protocol=registry
#dubbo.scan.base-packages=com.example.springboot.dubbo
用戶服務(wù)類:
package com.example.springboot.dubbo.service.impl;
import com.example.spring.dubbo.bean.UserAddress;
import com.example.spring.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Service//暴露服務(wù)
@Component
public class UserServiceImpl implements UserService {
@Override
public List getUserAddressList(String userId) {
UserAddress address1 = new UserAddress(1, "北京市昌平區(qū)", "1", "李老師", "010-56253825", "Y");
UserAddress address2 = new UserAddress(2, "深圳市寶安區(qū)", "1", "王老師", "010-56253825", "N");
return Arrays.asList(address1,address2);
}
}
Springboot的啟動類要加上@EnableDubbo注解:
package com.example.springboot.dubbo;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
* Springboot啟動類
*
*
* @author nicky
*
* 修改記錄
* 修改后版本: 修改人:修改日期: 2020年01月05日 修改內(nèi)容:
*
*/
@EnableDubbo(scanBasePackages="com.example.springboot.dubbo.service.impl")
@SpringBootApplication
public class UserServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceProviderApplication.class, args);
}
}
啟動Springboot類,然后在監(jiān)控平臺是可以看到服務(wù)注冊成功的

查看服務(wù)接口的詳細信息:

4.4、服務(wù)消費者工程
然后服務(wù)已經(jīng)注冊了,現(xiàn)在創(chuàng)建一個消費者工程order-service-comsumer
maven加上配置
2.2.1.RELEASE
2.7.5
2.12.0
org.springframework.boot
spring-boot-starter-web
org.apache.dubbo
dubbo-spring-boot-starter
${dubbo.version}
org.apache.dubbo
dubbo-dependencies-zookeeper
${dubbo.version}
pom
org.slf4j
slf4j-log4j12
org.apache.curator
curator-framework
${curator.version}
org.apache.curator
curator-recipes
${curator.version}
com.example.springboot
shop-api-common
0.0.1-SNAPSHOT
消費者配置文件:
server.port=8081
dubbo.application.name=order-service-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.monitor.protocol=registry
訂單服務(wù)類:
package com.example.springboot.dubbo.service.impl;
import com.example.spring.dubbo.bean.UserAddress;
import com.example.spring.dubbo.service.OrderService;
import com.example.spring.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import java.util.List;
/**
*
* 訂單服務(wù)
*
*
* @author nicky
*
* 修改記錄
* 修改后版本: 修改人:修改日期: 2020年01月05日 修改內(nèi)容:
*
*/
@Service
public class OrderServiceImpl implements OrderService{
@Reference(loadbalance="random",timeout=1000) //dubbo直連
UserService userService;
@Override
public List initOrder(String userId) {
//1、查詢用戶的收貨地址
List addressList = userService.getUserAddressList(userId);
return addressList;
}
}
Springboot啟動
package com.example.springboot.dubbo;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
* Springboot啟動類
*
*
* @author nicky
*
* 修改記錄
* 修改后版本: 修改人:修改日期: 2020年01月05日 修改內(nèi)容:
*
*/
@EnableDubbo(scanBasePackages="com.example.springboot.dubbo.service.impl")
@SpringBootApplication
public class OrderServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceProviderApplication.class, args);
}
}
寫一個Controller類進行測試:
package com.example.springboot.dubbo.controller;
import com.example.spring.dubbo.bean.UserAddress;
import com.example.spring.dubbo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class OrderController {
@Autowired
OrderService orderService;
@ResponseBody
@RequestMapping("/initOrder")
public List initOrder(@RequestParam("uid")String userId) {
return orderService.initOrder(userId);
}
}
在監(jiān)控平臺看,消費者啟動也是可以的


騰訊、阿里、滴滴后臺面試題匯總總結(jié) — (含答案)
面試:史上最全多線程面試題 !
最新阿里內(nèi)推Java后端面試題
JVM難學(xué)?那是因為你沒認(rèn)真看完這篇文章

關(guān)注作者微信公眾號 —《JAVA爛豬皮》
了解更多java后端架構(gòu)知識以及最新面試寶典


看完本文記得給作者點贊+在看哦~~~大家的支持,是作者源源不斷出文的動力
作者:SmileNicky
出處:https://www.cnblogs.com/mzq123/p/12153889.html
