Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、輕量級的開源 Java RPC 框架,它提
供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動註冊和html
發現。java
Dubbo 是一個分佈式服務框架,致力於提供高性能和透明化的 RPC 遠程服務調用方案、 服
務治理方案。
官網:http://dubbo.apache.org/zh-cn/node
快速開始文檔地址:http://dubbo.apache.org/zh-cn/docs/user/quick-start.htmlweb
面向接口代理:調用接口的方法,在 A 服務器調用 B 服務器的方法,由 dubbo 實現對 B 的
調用,無需關心實現的細節,就像 MyBatis 訪問 Dao 的接口,能夠操做數據庫同樣。不用關
心 Dao 接口方法的實現。這樣開發是方便,舒服的。redis
架構圖:算法
provider:提供者,供應商,提供程序spring
consumer:消費者數據庫
subscribe:訂閱apache
notify:通知服務器
invoke:調用,呼叫
服務提供者( (Provider) ):暴露服務的服務提供方,服務提供者在啓動時,向註冊中心注
冊本身提供的服務。
服務消費者( (Consumer ): 調用遠程服務的服務消費方,服務消費者在啓動時,向註冊
中心訂閱本身所需的服務,服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一
臺提供者進行調用,若是調用失敗,再選另外一臺調用。
註冊中心( (Registry) ):註冊中心返回服務提供者地址列表給消費者,若是有變動,註冊
中心將基於長鏈接推送變動數據給消費者
監控中心( (Monitor) ):服務消費者和提供者,在內存中累計調用次數和調用時間,定時
每分鐘發送一次統計數據到監控中心
調用關係說明:
⚫ 服務容器負責啓動,加載,運行服務提供者。
⚫ 服務提供者在啓動時,向註冊中心註冊本身提供的服務。
⚫ 服務消費者在啓動時,向註冊中心訂閱本身所需的服務。
⚫ 註冊中心返回服務提供者地址列表給消費者,若是有變動,註冊中心將基於長鏈接推送
變動數據給消費者。
⚫ 服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一臺提供者進行調用,如
果調用失敗,再選另外一臺調用。
⚫ 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數
據到監控中心。
支持多種協議:dubbo , hessian , rmi , http, webservice , thrift , memcached , redis。
dubbo 官方推薦使用 dubbo 協議。dubbo 協議默認端口 20880
使用 dubbo 協議,spring 配置文件加入:
<dubbo:protocol name="dubbo" port="20880" />
某電商平臺系統需求,用戶瀏覽商品;選擇商品下訂單,訂單系統須要獲取用戶信息中
的送貨地址;向支付系統請求完成付款。
點對點的直連項目:消費者直接訪問服務提供者,沒有註冊中心。消費者必須指定服務
提供者的訪問地址(url)。
消費者直接經過 url 地址訪問固定的服務提供者。這個 url 地址是不變的。
以 JavaSE 爲例,服務提供者,服務消費者都是 JavaSE 項目
項目名稱: link-orderservice-provider
設置 version 爲 1.0.0
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.16.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.2</version> </dependency>
在<build>中加入 plugin
<plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins>
package com.bjpowernode.domain; import java.io.Serializable; public class Order implements Serializable { private String id; private String goodName; private float price; private int amount; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getGoodName() { return goodName; } public void setGoodName(String goodName) { this.goodName = goodName; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } @Override public String toString() { return "Order{" + "id='" + id + '\'' + ", goodName='" + goodName + '\'' + ", price=" + price + ", amount=" + amount + '}'; } }
package com.bjpowernode.service; import com.bjpowernode.domain.Order; public interface OrderService { public Order createOrder(Integer userId,String goodName,float price,int amount); }
package com.bjpowernode.service.impl; import com.bjpowernode.domain.Order; import com.bjpowernode.service.OrderService; import java.util.UUID; public class OrderServiceImpl implements OrderService { public Order createOrder(Integer userId, String goodName, float price, int amount) { Order order=new Order(); order.setAmount(amount); order.setGoodName(goodName); order.setId(UUID.randomUUID().toString().replace("-","")); order.setPrice(price); System.out.println("建立訂單"+order); return order; } }
orderservce-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://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--聲明dubbo服務名稱--> <dubbo:application name="link-orderservice-provider"/> <!--聲明訪問dubbo服務的協議--> <dubbo:protocol name="dubbo" port="20880"/> <!--聲明服務的接口暴露服務--> <dubbo:service interface="com.bjpowernode.service.OrderService" ref="orderService" registry="N/A"/> <!--聲明接口的實現類對象--> <bean id="orderService" class="com.bjpowernode.service.impl.OrderServiceImpl"/> </beans>
package com.bjpowernode; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; public class OrderProviderApplication { public static void main(String[] args) throws IOException { String config="orderservice-provider.xml"; ApplicationContext context=new ClassPathXmlApplicationContext(config); //調用容器的啓動方法。 ((ClassPathXmlApplicationContext) context).start(); System.in.read(); } }
H 、 地 安裝本地 jar 到 到 maven
服務接口中的方法要給消費者使用,消費者項目須要知道接口名稱和接口中的方法名稱、參
數等。這些信息服務提供者才知道。須要把接口的 class 文件打包爲 jar .
服務接口項目的類文件打包爲 jar, 安裝到 maven 倉庫,倉庫中的提供者 jar 能夠被消費者
使用。
使用 idea 的 maven 窗口執行 install
項目名稱: link-main-web
<dependency> <groupId>com.bjpowernode</groupId> <artifactId>link-orderservice-provider</artifactId> <version>1.0.0</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.16.RELEASE</version> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.2</version> </dependency>
<build>加入 maven 編譯插件
<plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins>
package com.bjpowernode.service; import com.bjpowernode.domain.Order; public interface ShopService {
//用戶id,商品名稱,價格,數量 public Order buyGoods(Integer userId,String goodName,float price,int amount); }
package com.bjpowernode.service.impl; import com.bjpowernode.domain.Order; import com.bjpowernode.service.OrderService; import com.bjpowernode.service.ShopService; import com.sun.org.apache.xpath.internal.operations.Or; public class ShopServiceImpl implements ShopService {
//使用遠程服務接口 private OrderService orderService; public void setOrderService(OrderService orderService) { this.orderService = orderService; } @Override public Order buyGoods(Integer userId, String goodName, float price, int amount) { System.out.println("buyGoods訪問服務提供的方法"); System.out.println("代理:"+orderService.getClass().getName());
//調用遠程方法,建立訂單 Order order= orderService.createOrder(userId,goodName,price,amount); return order; } }
shop-consume.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.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!--聲明dubbo的服務名稱 name:dubbo的服務名稱,自定義的字符串,可使用項目的名稱。 服務的名稱最好是惟一值,dubbo框架內部用來區分服務的。 --> <dubbo:application name="link-main-web" /> <!--聲明要使用的遠程接口(服務提供者) id:dubbo建立的接口的實現類對象的名稱(動態代理) interface:遠程的接口全限定名稱(服務提供者中的接口) registry:表示是否使用註冊中心, 不使用賦值爲"N/A" url:訪問服務提供者的地址,直連方式中,地址是固定的。 http://localhost:8080/myweb dubbo://localhost:20880 --> <dubbo:reference id="remoteOrderService" interface="com.bjpowernode.service.OrderService" registry="N/A" url="dubbo://localhost:20880"> </dubbo:reference> <!--聲明自定義的業務對象--> <bean id="shopService" class="com.bjpowernode.service.impl.ShopServiceImpl"> <property name="orderService" ref="remoteOrderService"></property> </bean> </beans>
package com.bjpowernode; import com.bjpowernode.domain.Order; import com.bjpowernode.service.ShopService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ConsumeApplication { public static void main(String[] args) { String config = "main-consume.xml"; ApplicationContext context = new ClassPathXmlApplicationContext(config); ShopService shopService = (ShopService) context.getBean("shopService"); Order order = shopService.buyGoods(1, "thinkpad", 5999, 1); System.out.println(order); } }
建議將服務接口、服務模型、服務異常等均放在公共包中。
服務接口儘量大粒度,每一個服務方法應表明一個功能,而不是某功能的一個步驟,否
則將面臨分佈式事務問題,Dubbo 暫未提供分佈式事務支持。
服務接口建議以業務場景爲單位劃分,並對相近業務作抽象,防止接口數量爆炸。
不建議使用過於抽象的通用接口,如:Map query(Map),這樣的接口沒有明確語義,會
給後期維護帶來不便。
每一個接口都應定義版本號,爲後續不兼容升級提供可能,如: <dubbo:service
interface="com.xxx.XxxService" version="1.0" />。
建議使用兩位版本號,要變動服務版本。先升級一半提供者爲新版本,再將消費者所有
升爲新版本,而後將剩下的一半提供者升爲新版本。
抽象分散在多個項目中的公共接口,實體類,異常,工具類到一個項目中,在其餘項目
如服務提供者,消費者共用公共的資源。
用戶訪問電商網站瀏覽商品—選擇商品購買
用戶訪問電商網站—查看用戶信息(收件人地址)
Dubbo 中經常使用標籤。分爲三個類別:公用標籤,服務提供者標籤,服務消費者標籤
<dubbo:application/> 和 <dubbo:registry/>
<dubbo:application name=」服務的名稱」/>
<dubbo:registry address=」ip:port」 protocol=」協議」/>
<dubbo:service interface=」服務接口名」 ref=」服務實現對象 bean」>
<dubbo:reference id=」服務引用 bean 的 id」 interface=」服務接口名」/>