上手Dubbo之 環境搭建
- 2019 年 10 月 3 日
- 筆記
和傳統ssm整合–寫XML配置文件
搭建服務的提供者和服務的消費者,實現服務消費者跨應用遠程調用服務提供者
公共模組抽取
- 公共模組的抽取
服務的消費者遠程調用服務的提供者, 最起碼他自己要得到在服務提供者提供服務的那個類的引用, 那消費者和服務的一人一份,如果是集群就會翻倍,故抽取公共模組,存放公共使用的類和介面
服務提供者
- 依賴
// 自定義的公共模組 <dependency> <groupId>com.changwu</groupId> <artifactId>commom</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.3</version> </dependency>
- 編寫提供服務的業務Service, 對介面進行具體的實現
public class UserServiceImpl implements UserService { public List<UserAddress> getUserAddressList() { UserAddress a1= new UserAddress(1,"張三","北京市朝陽區"); UserAddress a2= new UserAddress(2,"李四","山東濟南"); return Arrays.asList(a1,a2); } }
- 編寫配置文件provider.xml,目的是作為服務的提供者將自己註冊進註冊中心, 暴露出自己的具體某個介面,為服務的消費者提供服務
<?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:dubbo="http://dubbo.apache.org/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 暴露服務提供者, name=服務名(不能和其他服務名重複) --> <dubbo:application name="user-service-provider" /> <!-- z指定zookeeper的地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 指定通訊規則,通訊協議, 通訊埠. 服務消費者和dubbo之間的通訊--> <dubbo:protocol name="dubbo" port="20880" /> <!-- 聲明需要暴露的服務介面 ref=服務的真正實現, 下面使用<bean>調用--> <dubbo:service interface="com.changwu.service.UserService" ref="userService" /> <!-- 介面的實現 --> <bean id="userService" class="com.changwu.service.impl.UserServiceImpl" /> <dubbo:monitor protocol="registry"></dubbo:monitor> </beans>
schema配置參考手冊, 點擊查看全部標籤,及詳細解釋
補充: 屬性配置的重寫覆蓋優先順序
- 優先順序最高 JVM 啟動時 使用-D設置參數
- 次之,dubbo.xml
- 再次之 dubbo.properties
如下,是一個典型的dubbo.properties配置樣例。
dubbo.application.name=foo dubbo.application.owner=bar dubbo.registry.address=10.20.153.10:9090
- idea設置虛擬機啟動參數
- log4j配置文件,(不添加的話會有警告)
###set log levels### log4j.rootLogger=info, stdout ###output to console### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n
服務的消費者
- 依賴
// 自定義的公共模組 <dependency> <groupId>com.changwu</groupId> <artifactId>commom</artifactId> <version>1.0-SNAPSHOT</version> </dependency> // zk的客戶端依賴 curator <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.13.0</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.13</version> </dependency>
- 編寫consumer.xml
編寫配置文件自己的服務名,配置註冊中心的地址,進而向註冊中心拉取服務的列表,配置當前的消費者中使用的哪些介面是通過遠程RPC調用實現的, 還可以配置監控中心查看服務的健康情況,彼此的調用情況,別忘了使用Spring註解還得配置包掃描
<?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:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 --> <dubbo:application name="order-service" /> <!--註冊中心地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 生成遠程服務代理,可以和本地bean一樣使用 userService --> <dubbo:reference id="userService" interface="com.changwu.service.UserService" /> <!--添加包掃描--> <context:component-scan base-package="com.changwu"></context:component-scan> <!--配置監控中心,有下面兩種方式 1. 去註冊中心自動發現, 2. 直連模式--> <dubbo:monitor protocol="registry"></dubbo:monitor> <!-- <dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor>--> </beans>
- 消費者調用服務提供者的實現
下面的@Service註解使用的Spring原生的
@Service // 沒有用dubbo的service註解 public class OrderServiceImpl implements OrderService { @Autowired UserService userService; public List initOrder(String userId) { // 查詢用戶的地址 System.out.println("userId == "+userId); List<UserAddress> userAddressList = userService.getUserAddressList("1"); for (UserAddress userAddress : userAddressList) { System.out.println(userAddress.getAdress()); } return userAddressList; } }
- 啟動測試
public class MainApp { public static void main(String[] args) { ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("consumer.xml"); OrderService orderService = ioc.getBean(OrderService.class); orderService.initOrder("1"); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
整合Springboot
公共模組
同樣重複使用類,介面放到中,然後在其它模組引用
服務提供者
- 依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.changwu</groupId> <artifactId>common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- dubbo整合進springboot zookeeper,curate它都已經導入進來了 --> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.2.0</version> </dependency>
- 將provider.xml配置文件替換成application.properties
可以將xml的tag名和屬性名組合起來,用『.』分隔。每行一個屬性
# 指定當前的服務, 一般為了防止重複,設置成當前module的名字 dubbo.application.name=provider # 指定註冊中心的地址 dubbo.registry.address=127.0.0.1:2181 dubbo.registry.protocol=zookeeper # dubbo 使用的協議 dubbo.protocol.name=dubbo dubbo.protocol.port=20880 # 原配置文件中暴露服務的名字,使用類似下面的方式,但是在SpringBoot中使用 @Service註解(dubbo的) # dubbo.service.interface=com.changwu.service.UserService # 監控中心 dubbo.monitor.protocol=registry server.port=8082
- 服務提供者對介面進行實現
@Service使用的dubbo的介面
@Component @Service //使用dubbo的Service 對外保留服務 public class UserServiceImpl implements UserService { public List<UserAddress> getUserAddressList(String userId) { UserAddress a1= new UserAddress(1,"張三","北京市朝陽區"); UserAddress a2= new UserAddress(2,"李四","山東濟南"); return Arrays.asList(a1,a2); } }
- 啟動類,開啟dubbo配置
@EnableDubbo @SpringBootApplication public class ProviderApp { public static void main(String[] args) { SpringApplication.run(ProviderApp.class); } }
服務的消費者
- 依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.changwu</groupId> <artifactId>common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.2.0</version> </dependency>
- 使用application.properties配置文件替換consumer.xml
# 告訴註冊中心自己的名字 dubbo.application.name=consumer # 註冊中心的地址 dubbo.registry.address=zookeeper://127.0.0.1:2181 # 配置監控中心 dubbo.monitor.protocol=registry # 原來在配置文件中使用 dubbo:reference 配置遠程調用的介面,現在用註解 server.port=8081
- 遠程調用@Reference dubbo註解
@Service public class OrderServiceImpl implements OrderService{ //@Autowired @Reference // dubbo的註解 UserService userService; public List<UserAddress> initOrder(String userId) { return userService.getUserAddressList("1"); } }
- 編寫Controller
- 啟動類, 開啟dubbo配置
@EnableDubbo @SpringBootApplication public class MainApp { public static void main(String[] args) { SpringApplication.run(MainApp.class); } }
其他常用配置
示例, dubbo常用的配置示例
啟動時檢查
服務的消費者在啟動是會去檢查自己需要遠程調用的服務是否已經註冊到了 註冊中心中, 一旦檢查到註冊中心沒有檢查到即使沒有調用這個方法也會自動報錯而阻止Spring啟動,在開發時,可以選擇手動關掉這個配置
- 通過配置文件
配置某個服務啟動時檢查 在服務消費者中,關閉某個服務的啟動時檢查 (沒有提供者時報錯): <dubbo:reference interface="com.foo.BarService" check="false" /> 統一配置全部服務啟動時不檢查 關閉所有服務的啟動時檢查 (沒有提供者時報錯): <dubbo:consumer check="false" /> 默認是true. 表示註冊中心不存在時報錯 關閉註冊中心啟動時檢查 (註冊訂閱失敗時報錯): <dubbo:registry check="false" />
- 通過dubbo.properties
dubbo.reference.com.foo.BarService.check=false dubbo.reference.check=false dubbo.consumer.check=false dubbo.registry.check=false
- 通過JVM參數
java -Ddubbo.reference.com.foo.BarService.check=false java -Ddubbo.reference.check=false java -Ddubbo.consumer.check=false java -Ddubbo.registry.check=false
超時設置
消費者遠程調用服務提供者, 服務提供者的實現邏輯可能存在大量的耗時操作,這是就可能存在大量的執行緒阻塞在這個方法上, 超時設置解決了這個問題,一旦在指定的時間內,依然沒有返回任何數據,同樣會立即返回,保證系統的可用
預設使用
如下,設置超時時間為3秒
<!-- 生成遠程服務代理,可以和本地bean一樣使用 userService --> <dubbo:reference id="userService" interface="com.changwu.service.UserService" timeout="3000"/>
從上圖中,我標記了他們的作用,最優先的就是方法級別, 介面次之 , 全局級別最低 , — 相同級別的消費者設置優先,提供者設置次之
重試次數
一般超時配置timeout 和 重試次數retries 配合使用
調用失敗後,會根據重試的次數再次嘗試遠程調用, 重試次數不包含第一次,如果我們配置的3, 算上第一次,最多嘗試調用四次
如果服務提供者存在集群, 消費者就會輪詢集群進行重試
- 冪等次數
- 查詢,刪除,修改(特點是,同樣的請求,同樣的參數無論執行多少次,產生的結果都是一樣的), 設置重試次數
- 非冪等
- 新增,不設置冪等次數, retries=0
<!-- 生成遠程服務代理,可以和本地bean一樣使用 userService --> <dubbo:reference id="userService" interface="com.changwu.service.UserService" retries="3" timeout="3000"/>
多版本
我們給系統的某些功能進行了升級,但是不能一下把升級後的程式碼一次性全部適用到集群中的全部機器上,使用多版本控制,先把集群中的一小部分機器進行升級,沒有出現不可用現象再逐步拓展規模,最終完成全部替換
新舊版本的服務提供者全部繼承同一個介面com.foo.BarService , 通過ref指向不同的實現Bean
老版本服務提供者配置: <dubbo:service interface="com.foo.BarService" version="1.0.0" ref="userService1" /> <bean id="userService1" class="xxx"> 新版本服務提供者配置: <dubbo:service interface="com.foo.BarService" version="2.0.0" ref="userService2"/> <bean id="userService2" class="yyy">
老版本服務消費者配置: <dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" /> 新版本服務消費者配置: <dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" /> 如果不需要區分版本,可以按照以下的方式配置 [1]: <dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
本地存根
如果想在服務的消費者發送遠程過程調用其他方法之前進行,進行參數的驗證,如,判空處理, 可以選擇使用本地存根
如, UserService 是某個服務提供者實現的, 消費者遠程調用這個服務,進行如下配置消費者在本地提供自己的實現,並判斷參數的合法性
public class UserServiceImpl implements UserService{ // 注入這個被服務提供者支援的介面 private final UserService userService; // 提供構造函數 public UserServiceImpl(UserService userService) { this.userService = userService; } @Override public List<UserAddress> getUserAddressList(String userId) { // 判空 if (!StringUtils.isEmpty(userId)){ return userService.getUserAddressList(userId); } return null; } }
- 配置文件
在 spring 配置文件中按以下方式配置: # 是消費者在本地自己的實現 com.changwu.service.UserServiceImpl <dubbo:service interface="com.changwu.service.UserServiceImpl" stub="true" /> 或 <dubbo:service interface="com.foo.BarService" stub="com.changwu.service.UserServiceImpl" />
Dubbo和SpringBoot整合的三種方式
方法1
- 引入dubbo-starter
- 在主配置類上使用@EnableDubbo (指定 包掃描規則)
- 在application.properties配置屬性
- 服務提供者: 使用 @Service 暴露服務
- 服務消費者: 使用 @Reference 引用服務
方法2
如果還想添加諸如方法級別的配置,則保留dubboxml的配置文件
- 在啟動類上去掉@EnableDubbo註解
- 在啟動類上添加@ImportResource(localtion="classpath:provider/consumer.xml")
- 去掉 application.properties 中的有關dubbo配置
- 服務提供者使用 provider.xml 配置文件
- 服務消費者是有 consumer.xml 配置文件
方法3 註解配置
要求使用dubbo為2.6.3