Dubbo是一個分佈式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。 微服務使用最普遍的框架就是SpringCloud跟Dubbo。Dubbo比較專一於服務治理這塊,而SpringCloud全家桶則提供了微服務的一整套解決方案html
Dubbo採用全Spring配置方式,透明化接入應用,對應用沒有任何API侵入,不論是Provider仍是Consumer均可以經過Spring的配置文件進行配置,配置完以後,就能夠像使用springbean同樣進行服務暴露和調用了,徹底看不到dubboapi的存在。Dubbo基於Spring的Schema擴展進行加載。java
如今還能夠經過 API 的方式進行調用。git
架構圖github
調用關係說明:web
連通性:連通性說明他們之間都存在着關係,好比說Provider,Consumer和Registry三者之間都是長鏈接,而Provider,Consumer向Registry註冊服務以及訂閱服務的時間都得向Monitor彙報算法
健壯性:而健壯性說明具備穩定性,好比說註冊中心對等集羣中的任意一臺宕掉後,將自動切換到另外一臺。就算註冊中心所有宕掉,服務者和消費者仍能夠經過本地緩存進行通信。spring
伸縮性:伸縮性就是能夠經過增長機器部署實例進行添加新的註冊中心和服務提供者apache
升級性:文檔中提到的對將來架構的設想,比起目前框架它的特色是能夠實現自動部署服務的本地代理以及能夠經過訪問壓力來自動增減服務提供者api
本demo中用的是Zookeeper 3.4.14版本,用哪一個版本都行,記得改下demo中的pom文件裏的ZK依賴配置就能夠。下載和安裝步驟能夠參考如下連接:http://www.javashuo.com/article/p-cweqhrkt-kx.html緩存
爲何採用Zookeeper?
本demo中採用Zookeeper做爲Dubbo的註冊中心時,ZK是一個樹型的目錄服務,支持變動推送,能夠做爲集羣的管理工具使用。能夠集中管理配置文件。
(1)服務提供者在初始化啓動時,會在Zookeeper下的Dubbo節點下的服務節點下的providers節點下的節點建立一個子節點並寫入URL,路徑相似爲 /dubbo/servicename/providers/ ,該路徑下的全部子節點均爲服務提供者。此時這些子節點都爲臨時節點,由於臨時節點的生命週期與客戶端會話相關,因此一旦提供者所在的機器出現故障致使提供者沒法提供服務,該臨時節點就會自動從Zookeeper刪除。
此時由於服務者,註冊中心,消費者之間是長鏈接,註冊中心能感知服務者宕機,會告知消費者。
而監控中心是Dubbo服務治理體系中重要的一部分,它須要知道全部的服務提供者和消費者的變化狀況 。因此它在啓動時會在服務節點上註冊一個watcher來監聽子節點變化,路徑爲 /dubbo/servicename/ ,因此它也能感知服務提供者的宕機。
(2)還有一個特性就是Zookeeper的節點結構設計(樹形),它以服務名和類型,也就是 /dubbo/servicename/類型 做爲節點路徑,符合Dubbo訂閱和通知的需求,保證了以服務爲粒度的變動通知,通知範圍易於控制。因此即便服務提供者和消費者頻繁變動,對Zookeeper的性能也不會形成多大影響。
建立Maven項目project,而後在工程裏面建立三大模塊moudle,分別爲: dubbo-api (公共服務接口) 、 dubbo-consumer(消費者,調用遠程服務)、 dubbo-provider(提供遠程服務)。
(1)其中須要在整個項目的pom.xml文件中添加相關依賴:這裏須要注意dubbo的版本問題,下面會講到,這裏插個眼先。
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>dubbo_demo</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>dubbo_consumer</module> <module>dubbo_provider</module> <module>dubbo_api</module> </modules> <packaging>pom</packaging> <name>dubbo_demo Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.4.RELEASE</version> </dependency> <!-- 添加 日誌依賴包 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.24</version> </dependency> <!-- 添加 dubbo 依賴包 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.3</version> </dependency> <!-- 添加 zookeeper 相關依賴包 --> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.14</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.8.0</version> </dependency> <!-- 添加 zkclient 依賴包 --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> </dependencies> <build> <finalName>dubbo_demo</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
(2) 建立dubbo_api moudle,在項目中定義服務接口:該接口需單獨打包,在服務提供方和消費方共享 在dubbo-api中定義服務接口DemoService,以下:
package com.test; public interface DemoService { public String sayHello(String name); }
(3)建立dubbo_provider moudle,而後在dubbo_provider中實現上述接口。爲何這裏能實現跨moudle調用接口而且完成接口實現,由於在provider的pom.xml文件中添加了dubbo_api做爲依賴,故能引入上述接口。如圖
其中接口實現類DemoServiceImpl代碼以下:
import com.test.DemoService; public class DemoServiceImpl implements DemoService { public String sayHello(String name) { return "hello"+name; } }
同時在此moudle下寫一個啓動測試類,便於後面啓動provider:
import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; public class ProviderTest { public static void main(String[] args){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:dubbo-provider.xml"); applicationContext.start(); System.out.println("Dubbo provider start,啓動服務提供.."); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
(4)建立dubbo_consumer moudle,而後在dubbo_consumer中寫一個啓動測試類,便於後面啓動consumer調用provider提供的服務:
import com.test.DemoService; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; public class ConsumerTest { public static void main(String[] args){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:dubbo-consumer.xml"); applicationContext.start(); DemoService demoService = (DemoService) applicationContext.getBean("ddemoService"); System.out.println(demoService.sayHello(" guy")); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
(5)上述代碼寫好後,好像各個moudle看起來好像沒有聯繫?你們都好奇就是Dubbo是怎麼實現服務的發佈和遠程調用的吧。接下來是重點,進行provider和consumer的配置
a. 在dubbo_provider的resource中新建dubbo_provider.xml文件,實現dubbo中provider的配置:
首先完成應用配置,配置當前提供方應用名爲dubbo_provider。
而後完成註冊中心配置,將Zookeeper做爲註冊中心,設定其地址。
而後進行協議配置,用於配置提供服務的協議信息,協議只由provider指定,使用port="20880"做爲服務提供的接口,供consumer調用。
最後進行服務配置,用於暴露一個服務接口,其絕對路徑interface="com.test.DemoService",代號爲ref="demoService"
這裏還須要爲接口實現類配置一個bean,以供在provider的啓動測試類中調用bean中的方法。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 提供方應用信息,用於計算依賴關係 --> <dubbo:application name="dubbo_provider" /> <!-- 使用zookeeper註冊中心暴露服務地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 用dubbo協議在20880端口暴露服務 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 和本地bean同樣實現服務 --> <bean id="demoService" class="DemoServiceImpl" /> <!-- 聲明須要暴露的服務接口 --> <dubbo:service interface="com.test.DemoService" ref="demoService" /> </beans>
b. 在dubbo_consumer的resource中新建dubbo_consumer.xml文件,實現dubbo中consumer的配置。
首先完成應用配置,配置當前消費方應用名爲dubbo_consumer;
而後完成完成註冊中心配置,將Zookeeper做爲註冊中心,設定其地址。消費方向註冊中心訂閱本身所需的服務;
最後生成遠程服務代理,調用到了絕對路徑爲interface="com.test.DemoService" 的接口,設定其代號爲id="ddemoService",能夠和本地bean同樣使用ddemoService、
(這裏可能你們有個問題,爲何這裏多了個d,由於爲了和dubbo_provider.xml暴露的服務接口和bean作區別。說明消費方調用到此接口服務後,至關於本身的本地有了這個接口,因此接口名能夠和provider的不同。至關於我在別人那裏拿了一個蘋果,在我這裏我就能夠不叫他蘋果,我叫他梨也能夠,由於這個東西是在我手上(本地),我怎麼用本地都清楚,不須要外人(provider)清楚)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方同樣 --> <dubbo:application name="dubbo_consumer" /> <!-- 使用zookeeper註冊中心暴露發現服務地址 --> <dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181" /> <!-- 生成遠程服務代理,能夠和本地bean同樣使用demoService --> <dubbo:reference id="ddemoService" interface="com.test.DemoService" /> </beans>
(6)項目結構以下,具體能夠在文末下載本項目demo。
依次啓動zookeeper(打開bin文件下的zkServer.cmd,而且不要關閉。若是閃退的會能夠用cmd調用文件名打開)、運行dubbo-provider、運行dubbo-consumer得到測試結果以下。
本項目遇到了一個比較奇葩的問題找了我一天,每次在運行provider和consumer的時候都會出現下述問題。
問題:找不到Spring命名空間處理程序。
Offending resource: class path resource [dubbo-consumer.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://dubbo.apache.org/schema/dubbo]
Offending resource: class path resource [dubbo-consumer.xml]
就是下圖紅框的兩個地址有問題,但是這兩個地址都是能夠打開的。
問題所在:最終發現以前有段時間dubbo被關閉了一段時間,那段時間dubbo的域名是code.alibabatech.com ,網上找到別人的案例裏面配置的都是下面這種地址,結果發現這些地址都失效。按道理我如今程序裏用最新的應該沒錯,爲何還會報錯了。又只能繼續處處找bug。
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
後來開始懷疑是否是我一開始用的版本比較舊(2.5.X);而後發現果真如此。問題在於: dubbo-config-spring-2.6.1.jar --> META-INF-->spring.handlers 中的配置仍是以前的域名 code.alibabatech.com , 可是這個域名已經不可用了,因此用dubbo舊版本的須要注意下這個問題(參考https://blog.csdn.net/huweijun_2012/article/details/80239803)
可是如今2.6.2以上都版本都不出現這個問題了,spring.handlers 中的配置仍是以前的域名 包含舊的和新的域名,至關於能夠兼容。可是因爲code.alibabatech.com 域名已經不可用,因此解決辦法只能是在pom.xml文件中修改dubbo的版本,使用至少2.6.2以上版本就不會出現此問題。
本文demo下載地址:(個人git還沒空弄,後續補上~)
連接: https://pan.baidu.com/s/1d4iPfCu21CKfaW_T8_QMFA 提取碼: 74wn
本文參考:
http://dubbo.apache.org/zh-cn/docs/user/quick-start.html
http://www.javashuo.com/article/p-mluvmral-nn.html
http://www.javashuo.com/article/p-cweqhrkt-kx.html
https://blog.csdn.net/huweijun_2012/article/details/80239803