Dubbo詳細(xì)介紹與安裝使用過程

1 Dubbo介紹

網(wǎng)站建設(shè)、成都網(wǎng)站制作的關(guān)注點(diǎn)不是能為您做些什么網(wǎng)站,而是怎么做網(wǎng)站,有沒有做好網(wǎng)站,給創(chuàng)新互聯(lián)一個(gè)展示的機(jī)會(huì)來證明自己,這并不會(huì)花費(fèi)您太多時(shí)間,或許會(huì)給您帶來新的靈感和驚喜。面向用戶友好,注重用戶體驗(yàn),一切以用戶為中心。

1.1 dubbox簡介

隨著互聯(lián)網(wǎng)的發(fā)展,網(wǎng)站應(yīng)用的規(guī)模不斷擴(kuò)大,常規(guī)的垂直應(yīng)用架構(gòu)已無法應(yīng)對,分布式服務(wù)架構(gòu)以及流動(dòng)計(jì)算架構(gòu)勢在必行,亟需一個(gè)治理系統(tǒng)確保架構(gòu)有條不紊的演進(jìn)。

Dubbo詳細(xì)介紹與安裝使用過程

單一應(yīng)用架構(gòu)?

當(dāng)網(wǎng)站流量很小時(shí),只需一個(gè)應(yīng)用,將所有功能都部署在一起,以減少部署節(jié)點(diǎn)和成本。?

此時(shí),用于簡化增刪改查工作量的 數(shù)據(jù)訪問框架(ORM) 是關(guān)鍵。

垂直應(yīng)用架構(gòu)?

當(dāng)訪問量逐漸增大,單一應(yīng)用增加機(jī)器帶來的加速度越來越小,將應(yīng)用拆成互不相干的幾個(gè)應(yīng)用,以提升效率。?

此時(shí),用于加速前端頁面開發(fā)的 Web框架(MVC) 是關(guān)鍵。

分布式服務(wù)架構(gòu)?

當(dāng)垂直應(yīng)用越來越多,應(yīng)用之間交互不可避免,將核心業(yè)務(wù)抽取出來,作為獨(dú)立的服務(wù),逐漸形成穩(wěn)定的服務(wù)中心,使前端應(yīng)用能更快速的響應(yīng)多變的市場需求。?

此時(shí),用于提高業(yè)務(wù)復(fù)用及整合的 分布式服務(wù)框架(RPC) 是關(guān)鍵。

流動(dòng)計(jì)算架構(gòu)?

當(dāng)服務(wù)越來越多,容量的評估,小服務(wù)資源的浪費(fèi)等問題逐漸顯現(xiàn),此時(shí)需增加一個(gè)調(diào)度中心基于訪問壓力實(shí)時(shí)管理集群容量,提高集群利用率。?

此時(shí),用于提高機(jī)器利用率的 資源調(diào)度和治理中心(SOA) 是關(guān)鍵。

dubbox是dubbo的擴(kuò)展,主要在dubbo的基礎(chǔ)上進(jìn)行了一下的改進(jìn):

1、支持REST風(fēng)格遠(yuǎn)程調(diào)用(HTTP + JSON/XML):基于非常成熟的JBoss RestEasy框架,在dubbo中實(shí)現(xiàn)了REST風(fēng)格(HTTP + JSON/XML)的遠(yuǎn)程調(diào)用,以顯著簡化企業(yè)內(nèi)部的跨語言交互,同時(shí)顯著簡化企業(yè)對外的Open API、無線API甚至AJAX服務(wù)端等等的開發(fā)。事實(shí)上,這個(gè)REST調(diào)用也使得Dubbo可以對當(dāng)今特別流行的“微服務(wù)”架構(gòu)提供基礎(chǔ)性支持。 另外,REST調(diào)用也達(dá)到了比較高的性能,在基準(zhǔn)測試下,HTTP + JSON與Dubbo 2.x默認(rèn)的RPC協(xié)議(即TCP + Hessian2二進(jìn)制序列化)之間只有1.5倍左右的差距,詳見文檔中的基準(zhǔn)測試報(bào)告。

2、支持基于Kryo和FST的Java高效序列化實(shí)現(xiàn):基于當(dāng)今比較知名的Kryo和FST高性能序列化庫,為Dubbo默認(rèn)的RPC協(xié)議添加新的序列化實(shí)現(xiàn),并優(yōu)化調(diào)整了其序列化體系,比較顯著的提高了Dubbo RPC的性能,詳見文檔中的基準(zhǔn)測試報(bào)告。

3、支持基于Jackson的JSON序列化:基于業(yè)界應(yīng)用最廣泛的Jackson序列化庫,為Dubbo默認(rèn)的RPC協(xié)議添加新的JSON序列化實(shí)現(xiàn)。

4、支持基于嵌入式Tomcat的HTTP remoting體系:基于嵌入式tomcat實(shí)現(xiàn)dubbo的HTTP remoting體系(即dubbo-remoting-http),用以逐步取代Dubbo中舊版本的嵌入式Jetty,可以顯著的提高REST等的遠(yuǎn)程調(diào)用性能,并將Servlet API的支持從2.5升級到3.1。(注:除了REST,dubbo中的WebServices、Hessian、HTTP Invoker等協(xié)議都基于這個(gè)HTTP remoting體系)。

5、升級Spring:將dubbo中Spring由2.x升級到目前最常用的3.x版本,減少版本沖突帶來的麻煩。

6、升級ZooKeeper客戶端:將dubbo中的zookeeper客戶端升級到最新的版本,以修正老版本中包含的bug。

7、支持完全基于Java代碼的Dubbo配置:基于Spring的Java Config,實(shí)現(xiàn)完全無XML的純Java代碼方式來配置dubbo

8、調(diào)整Demo應(yīng)用:暫時(shí)將dubbo的demo應(yīng)用調(diào)整并改寫以主要演示REST功能、Dubbo協(xié)議的新序列化方式、基于Java代碼的Spring配置等等。?

9、修正了dubbo的bug 包括配置、序列化、管理界面等等的bug。

1.2 dubbo架構(gòu)構(gòu)成

dubbo運(yùn)行架構(gòu)如下圖示:

Dubbo詳細(xì)介紹與安裝使用過程

節(jié)點(diǎn)角色說明:

1、Provider:暴露服務(wù)的服務(wù)提供方。 Consumer: 調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費(fèi)方。

2、Registry:服務(wù)注冊與發(fā)現(xiàn)的注冊中心。 Monitor: 統(tǒng)計(jì)服務(wù)的調(diào)用次調(diào)和調(diào)用時(shí)間的監(jiān)控中心。

3、Container: 服務(wù)運(yùn)行容器。

調(diào)用關(guān)系說明:?

1、服務(wù)容器負(fù)責(zé)啟動(dòng),加載,運(yùn)行服務(wù)提供者。?

2、服務(wù)提供者在啟動(dòng)時(shí),向注冊中心注冊自己提供的服務(wù)。?

3、服務(wù)消費(fèi)者在啟動(dòng)時(shí),向注冊中心訂閱自己所需的服務(wù)。?

4、注冊中心返回服務(wù)提供者地址列表給消費(fèi)者,如果有變更,注冊中心將基于長連接推送變更數(shù)據(jù)給消費(fèi)者。?

5、服務(wù)消費(fèi)者,從提供者地址列表中,基于軟負(fù)載均衡算法,選一臺(tái)提供者進(jìn)行調(diào)用,如果調(diào)用失敗,再選另一臺(tái)調(diào)用。?

6、服務(wù)消費(fèi)者和提供者,在內(nèi)存中累計(jì)調(diào)用次數(shù)和調(diào)用時(shí)間,定時(shí)每分鐘發(fā)送一次統(tǒng)計(jì)數(shù)據(jù)到監(jiān)控中心。

1.3 dubbo的特性

(1) 連通性:

注冊中心負(fù)責(zé)服務(wù)地址的注冊與查找,相當(dāng)于目錄服務(wù),服務(wù)提供者和消費(fèi)者只在啟動(dòng)時(shí)與注冊中心交互,注冊中心不轉(zhuǎn)發(fā)請求,壓力較小監(jiān)控中心負(fù)責(zé)統(tǒng)計(jì)各服務(wù)調(diào)用次數(shù),調(diào)用時(shí)間等,統(tǒng)計(jì)先在內(nèi)存匯總后每分鐘一次發(fā)送到監(jiān)控中心服務(wù)器,并以報(bào)表展示服務(wù)提供者向注冊中心注冊其提供的服務(wù),并匯報(bào)調(diào)用時(shí)間到監(jiān)控中心,此時(shí)間不包含網(wǎng)絡(luò)開銷服務(wù)消費(fèi)者向注冊中心獲取服務(wù)提供者地址列表,并根據(jù)負(fù)載算法直接調(diào)用提供者,同時(shí)匯報(bào)調(diào)用時(shí)間到監(jiān)控中心,此時(shí)間包含網(wǎng)絡(luò)開銷注冊中心,服務(wù)提供者,服務(wù)消費(fèi)者三者之間均為長連接,監(jiān)控中心除外注冊中心通過長連接感知服務(wù)提供者的存在,服務(wù)提供者宕機(jī),注冊中心將立即推送事件通知消費(fèi)者注冊中心和監(jiān)控中心全部宕機(jī),不影響已運(yùn)行的提供者和消費(fèi)者,消費(fèi)者在本地緩存了提供者列表?

注冊中心和監(jiān)控中心都是可選的,服務(wù)消費(fèi)者可以直連服務(wù)提供者

(2) 健狀性:

監(jiān)控中心宕掉不影響使用,只是丟失部分采樣數(shù)據(jù)數(shù)據(jù)庫宕掉后,注冊中心仍能通過緩存提供服務(wù)列表查詢,但不能注冊新服務(wù)注冊中心對等集群,任意一臺(tái)宕掉后,將自動(dòng)切換到另一臺(tái)注冊中心全部宕掉后,服務(wù)提供者和服務(wù)消費(fèi)者仍能通過本地緩存通訊服務(wù)提供者無狀態(tài),任意一臺(tái)宕掉后,不影響使用服務(wù)提供者全部宕掉后,服務(wù)消費(fèi)者應(yīng)用將無法使用,并無限次重連等待服務(wù)提供者恢復(fù)

(3) 伸縮性:

注冊中心為對等集群,可動(dòng)態(tài)增加機(jī)器部署實(shí)例,所有客戶端將自動(dòng)發(fā)現(xiàn)新的注冊中心?

服務(wù)提供者無狀態(tài),可動(dòng)態(tài)增加機(jī)器部署實(shí)例,注冊中心將推送新的服務(wù)提供者信息給消費(fèi)者

(4) 升級性:

當(dāng)服務(wù)集群規(guī)模進(jìn)一步擴(kuò)大,帶動(dòng)IT治理結(jié)構(gòu)進(jìn)一步升級,需要實(shí)現(xiàn)動(dòng)態(tài)部署,進(jìn)行流動(dòng)計(jì)算,現(xiàn)有分布式服務(wù)架構(gòu)不會(huì)帶來阻力:

Dubbo詳細(xì)介紹與安裝使用過程

1.4 dubbo的調(diào)用方式

異步調(diào)用

基于NIO的非阻塞實(shí)現(xiàn)并行調(diào)用,客戶端不需要啟動(dòng)多線程即可完成并行調(diào)用多個(gè)遠(yuǎn)程服務(wù),相對多線程開銷較小。

Dubbo詳細(xì)介紹與安裝使用過程

本地調(diào)用

本地調(diào)用,使用了Injvm協(xié)議,是一個(gè)偽協(xié)議,它不開啟端口,不發(fā)起遠(yuǎn)程調(diào)用,只在JVM內(nèi)直接關(guān)聯(lián),但執(zhí)行Dubbo的Filter鏈。

Define injvm protocol:

<dubbo:protocol name="injvm" />

Set default protocol:

<dubbo:provider protocol="injvm" />

Set service protocol:

<dubbo:service protocol="injvm" />

Use injvm first:

<dubbo:consumer injvm="true" .../>

<dubbo:provider injvm="true" .../>

<dubbo:reference injvm="true" .../>

<dubbo:service injvm="true" .../>

注意:服務(wù)暴露與服務(wù)引用都需要聲明injvm=“true”

1.5 dubbo支持的注冊中心

Dubbo提供的注冊中心有如下幾種類型可供選擇:

Multicast注冊中心

Zookeeper注冊中心

redis注冊中心

Simple注冊中心

ZooKeeper是一個(gè)開源的分布式服務(wù)框架,它是Apache Hadoop項(xiàng)目的一個(gè)子項(xiàng)目,主要用來解決分布式應(yīng)用場景中存在的一些問題,如:統(tǒng)一命名服務(wù)、狀態(tài)同步服務(wù)、集群管理、分布式應(yīng)用配置管理等,它支持Standalone模式和分布式模式,在分布式模式下,能夠?yàn)榉植际綉?yīng)用提供高性能和可靠地協(xié)調(diào)服務(wù),而且使用ZooKeeper可以大大簡化分布式協(xié)調(diào)服務(wù)的實(shí)現(xiàn),為開發(fā)分布式應(yīng)用極大地降低了成本。

ZooKeeper總體架構(gòu)

Dubbo詳細(xì)介紹與安裝使用過程

ZooKeeper集群由一組Server節(jié)點(diǎn)組成,這一組Server節(jié)點(diǎn)中存在一個(gè)角色為Leader的節(jié)點(diǎn),其他節(jié)點(diǎn)都為Follower。當(dāng)客戶端Client連接到ZooKeeper集群,并且執(zhí)行寫請求時(shí),這些請求會(huì)被發(fā)送到Leader節(jié)點(diǎn)上,然后Leader節(jié)點(diǎn)上數(shù)據(jù)變更會(huì)同步到集群中其他的Follower節(jié)點(diǎn)。

1.6 dubbo支持的遠(yuǎn)程通信協(xié)議

遠(yuǎn)程通信需要指定通信雙方所約定的協(xié)議,在保證通信雙方理解協(xié)議語義的基礎(chǔ)上,還要保證高效、穩(wěn)定的消息傳輸。Dubbo繼承了當(dāng)前主流的網(wǎng)絡(luò)通信框架,主要包括如下幾個(gè):

Mina

Netty

Grizzly

Dubbo詳細(xì)介紹與安裝使用過程

1.7 dubbo支持的遠(yuǎn)程調(diào)用協(xié)議

Dubbo支持多種協(xié)議,如下所示:

Dubbo協(xié)議

Hessian協(xié)議

HTTP協(xié)議

RMI協(xié)議

WebService協(xié)議

Thrift協(xié)議

Memcached協(xié)議

Redis協(xié)議

Dubbo詳細(xì)介紹與安裝使用過程

在通信過程中,不同的服務(wù)等級一般對應(yīng)著不同的服務(wù)質(zhì)量,那么選擇合適的協(xié)議便是一件非常重要的事情。你可以根據(jù)你應(yīng)用的創(chuàng)建來選擇。例如,使用RMI協(xié)議,一般會(huì)受到防火墻的限制,所以對于外部與內(nèi)部進(jìn)行通信的場景,就不要使用RMI協(xié)議,而是基于HTTP協(xié)議或者Hessian協(xié)議。

1.8 dubbo集群容錯(cuò)和負(fù)載均衡

1、集群容錯(cuò)?

在集群調(diào)用失敗時(shí),Dubbo提供了多種容錯(cuò)方案,缺省為failover重試。

Failover Cluster?

失敗自動(dòng)切換,當(dāng)出現(xiàn)失敗,重試其它服務(wù)器。(缺省)?

通常用于讀操作,但重試會(huì)帶來更長延遲。?

可通過retries=“2”來設(shè)置重試次數(shù)(不含第一次)。

Failfast Cluster?

快速失敗,只發(fā)起一次調(diào)用,失敗立即報(bào)錯(cuò)。?

通常用于非冪等性的寫操作,比如新增記錄。

Failsafe Cluster?

失敗安全,出現(xiàn)異常時(shí),直接忽略。?

通常用于寫入審計(jì)日志等操作。

Failback Cluster?

失敗自動(dòng)恢復(fù),后臺(tái)記錄失敗請求,定時(shí)重發(fā)。?

通常用于消息通知操作。

Forking Cluster?

并行調(diào)用多個(gè)服務(wù)器,只要一個(gè)成功即返回。?

通常用于實(shí)時(shí)性要求較高的讀操作,但需要浪費(fèi)更多服務(wù)資源。?

可通過forks=“2”來設(shè)置最大并行數(shù)。

Broadcast Cluster?

廣播調(diào)用所有提供者,逐個(gè)調(diào)用,任意一臺(tái)報(bào)錯(cuò)則報(bào)錯(cuò)。(2.1.0開始支持)?

通常用于通知所有提供者更新緩存或日志等本地資源信息。

2、負(fù)載均衡?

- Random LoadBalance隨機(jī),按權(quán)重設(shè)置隨機(jī)概率。?

在一個(gè)截面上碰撞的概率高,但調(diào)用量越大分布越均勻,而且按概率使用權(quán)重后也比較均勻,有利于動(dòng)態(tài)調(diào)整提供者權(quán)重。

RoundRobin LoadBalance 輪循,按公約后的權(quán)重設(shè)置輪循比率。?

存在慢的提供者累積請求問題,比如:第二臺(tái)機(jī)器很慢,但沒掛,當(dāng)請求調(diào)到第二臺(tái)時(shí)就卡在那,久而久之,所有請求都卡在調(diào)到第二臺(tái)上。

LeastActive LoadBalance 最少活躍調(diào)用數(shù),相同活躍數(shù)的隨機(jī),活躍數(shù)指調(diào)用前后計(jì)數(shù)差。?

使慢的提供者收到更少請求,因?yàn)樵铰奶峁┱叩恼{(diào)用前后計(jì)數(shù)差會(huì)越大。

ConsistentHash LoadBalance 一致性Hash,相同參數(shù)的請求總是發(fā)到同一提供者。?

當(dāng)某一臺(tái)提供者掛時(shí),原本發(fā)往該提供者的請求,基于虛擬節(jié)點(diǎn),平攤到其它提供者,不會(huì)引起劇烈變動(dòng)。

配置如:

<dubbo:service interface="..." loadbalance="roundrobin" />

1.9 dubbo源代碼結(jié)構(gòu)

Dubbo詳細(xì)介紹與安裝使用過程

Dubbo以包結(jié)構(gòu)來組織各個(gè)模塊,各個(gè)模塊及其關(guān)系,如圖所示:

Dubbo詳細(xì)介紹與安裝使用過程

dubbo-common 公共邏輯模塊,包括Util類和通用模型。

dubbo-remoting 遠(yuǎn)程通訊模塊,相當(dāng)于Dubbo協(xié)議的實(shí)現(xiàn),如果RPC用RMI協(xié)議則不需要使用此包。

dubbo-rpc 遠(yuǎn)程調(diào)用模塊,抽象各種協(xié)議,以及動(dòng)態(tài)代理,只包含一對一的調(diào)用,不關(guān)心集群的管理。

dubbo-cluster 集群模塊,將多個(gè)服務(wù)提供方偽裝為一個(gè)提供方,包括:負(fù)載均衡、容錯(cuò)、路由等,集群的地址列表可以是靜態(tài)配置的,也可以是由注冊中心下發(fā)。

dubbo-registry 注冊中心模塊,基于注冊中心下發(fā)地址的集群方式,以及對各種注冊中心的抽象。

dubbo-monitor 監(jiān)控模塊,統(tǒng)計(jì)服務(wù)調(diào)用次數(shù),調(diào)用時(shí)間的,調(diào)用鏈跟蹤的服務(wù)。

dubbo-config 配置模塊,是Dubbo對外的API,用戶通過Config使用Dubbo,隱藏Dubbo所有細(xì)節(jié)。

dubbo-container 容器模塊,是一個(gè)Standalone的容器,以簡單的Main加載Spring啟動(dòng),因?yàn)榉?wù)通常不需要Tomcat/JBoss等Web容器的特性,沒必要用Web容器去加載服務(wù)。

1.10 Dubbo內(nèi)核實(shí)現(xiàn)之SPI簡單介紹

Dubbo采用微內(nèi)核+插件體系,使得設(shè)計(jì)優(yōu)雅,擴(kuò)展性強(qiáng)。那所謂的微內(nèi)核+插件體系是如何實(shí)現(xiàn)的呢!即我們定義了服務(wù)接口標(biāo)準(zhǔn),讓廠商去實(shí)現(xiàn)(如果不了解spi的請谷歌百度下), jdk通過ServiceLoader類實(shí)現(xiàn)spi機(jī)制的服務(wù)查找功能。

JDK實(shí)現(xiàn)spi服務(wù)查找: ServiceLoader

首先定義下示例接口

package com.example;

public interface Spi {

? ? ? ?booleanisSupport(String name);

? ? ? ?String sayHello();

}

ServiceLoader會(huì)遍歷所有jar查找META-INF/services/com.example.Spi文件

A廠商提供實(shí)現(xiàn)

package com.a.example;

public class SpiAImpl implements Spi {

? ? ? ?publicboolean isSupport(String name) {

? ? ? ? ? ?return"SPIA".equalsIgnoreCase(name.trim());?

? ? ? ?}

? ? ? ? public String syaHello() {

? ? ? ? ? ?return “hello 我是廠商A”;

? ? ? ? }

}

在A廠商提供的jar包中的META-INF/services/com.example.Spi文件內(nèi)容為:

com.a.example.SpiAImpl #廠商A的spi實(shí)現(xiàn)全路徑類名

B廠商提供實(shí)現(xiàn)

package com.b.example;

public class SpiBImpl implements Spi {

? ? ? ?publicboolean isSupport(String name) {

? ? ? ? ? ? ? return"SPIB".equalsIgnoreCase(name.trim());?

? ? ? ?}

? ? ? ?public String syaHello() {?

? ? ? ? ? ? ?return “hello 我是廠商B”;

? ? ? ?}

}

在B廠商提供的jar包中的META-INF/services/com.example.Spi文件內(nèi)容為:

com.b.example.SpiBImpl #廠商B的spi實(shí)現(xiàn)全路徑類名

ServiceLoader.load(Spi.class)讀取廠商A、B提供jar包中的文件,ServiceLoader實(shí)現(xiàn)了Iterable接口可通過while for循環(huán)語句遍歷出所有實(shí)現(xiàn)。

一個(gè)接口多種實(shí)現(xiàn),就如策略模式一樣提供了策略的實(shí)現(xiàn),但是沒有提供策略的選擇, 使用方可以根據(jù)isSupport方法根據(jù)業(yè)務(wù)傳入廠商名來選擇具體的廠商。

public class SpiFactory {

? ? ? ?//讀取配置獲取所有實(shí)現(xiàn)

? ? ? ?privatestatic ServiceLoader spiLoader = ServiceLoader.load(Spi.class);

? ? ? //根據(jù)名字選取對應(yīng)實(shí)現(xiàn)

? ? ? publicstatic Spi getSpi(String name) {

? ? ? ? ? ? ? for(Spi spi : spiLoader) {

? ? ? ? ? ? ? ? ? ? if(spi.isSupport(name) ) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? returnspi;

? ? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? }

? ? ? ? ? ? ? returnnull;

? ? ? ? }

}

SPI接口定義

定義了@SPI注解

public @interface SPI {

? ? ? ?Stringvalue() default ""; //指定默認(rèn)的擴(kuò)展點(diǎn)

}?

只有在接口打了@SPI注解的接口類才會(huì)去查找擴(kuò)展點(diǎn)實(shí)現(xiàn),會(huì)依次從這幾個(gè)文件中讀取擴(kuò)展點(diǎn)

META-INF/dubbo/internal/ //dubbo內(nèi)部實(shí)現(xiàn)的各種擴(kuò)展都放在了這個(gè)目錄了

META-INF/dubbo/

META-INF/services/

我們以Protocol接口為例, 接口上打上SPI注解,默認(rèn)擴(kuò)展點(diǎn)名字為dubbo

@SPI("dubbo")

public interface Protocol{

}

具體實(shí)現(xiàn)的類有:

Dubbo詳細(xì)介紹與安裝使用過程

所以說:Remoting實(shí)現(xiàn)是Dubbo協(xié)議的實(shí)現(xiàn)

2 Dubbo架構(gòu)部署搭建

2.1 準(zhǔn)備工作

在開始搭建dubbox服務(wù)架構(gòu)前需要完成以下準(zhǔn)備工作:

下載安裝運(yùn)行zookeeper 具體安裝過程詳見zookeeper官網(wǎng):http://zookeeper.apache.org/ 使用版本為3.4.7

下載安裝tomcat 具體安裝過程詳見zookeeper官網(wǎng):http://tomcat.apache.org/ 使用版本為:7.0.67

下載dubbox代碼 github地址:http://dangdangdotcom.github.io/dubbox

2.2 build dubbox源碼

下載好dubbox的源代碼之后,可以看到dubbox的項(xiàng)目架構(gòu)構(gòu)成如下:

Dubbo詳細(xì)介紹與安裝使用過程

從上圖可以看出dubbox包含的各個(gè)組件和功能模塊。?

其中dubbo-admin為dubbox的監(jiān)控管理平臺(tái)。dubbo-demo中有提供一些dubbox的各種使用實(shí)例。我們通過運(yùn)行dubbo-demo中提供的功能實(shí)例來了解dubbox的使用和大致運(yùn)行原理。

在dubbox中的官方github中提供了如下的說明:

1、git clone https://github.com/dangdangdotcom/dubbox

2、在checkout出來的dubbox目錄執(zhí)行mvn install -Dmaven.test.skip=true來嘗試編譯一下dubbo(并將dubbo的jar安裝到本地maven庫)

3、在checkout出來的dubbox根目錄執(zhí)行mvn idea:idea或者mvn?

eclipse:eclipse,來創(chuàng)建IDE工程文件

4、將項(xiàng)目導(dǎo)入IDE

5、下載解壓一個(gè)zookeeper,編輯其conf/zoo.cfg后啟動(dòng)zookeeper用作dubbo注冊中心:bin/zkServer.sh start

6、用IDE運(yùn)行/dubbo-demo/dubbo-demo-provider/…/test目錄下的DemoProvider啟動(dòng)dubbo服務(wù)端,目前他會(huì)分別啟動(dòng)dubbo協(xié)議(包括用kryo和FST序列化)和REST協(xié)議的服務(wù)

7、用IDE運(yùn)行/dubbo-demo/dubbo-demo-consumer/…/test目錄下的DemoConsumer來啟動(dòng)dubbo客戶端調(diào)用上面的服務(wù)端,直接看console的輸出即可

8、用IDE運(yùn)行/dubbo-demo/dubbo-demo-consumer/…/test目錄下的RestClient來啟動(dòng)rest客戶端(模擬非dubbo的rest客戶端)調(diào)用上面的服務(wù)端,直接看console的輸出即可

9、可以在瀏覽器中直接訪問http://localhost:8888/services/users/100.xml或者h(yuǎn)ttp://localhost:8888/services/users/101.json之類來測試REST服務(wù)

10、了解tomcat和IDE集成的同事,可以直接在IDE中將/dubbo-demo/dubbo-demo-provider/部署到tomcat上,用tomcat的servlet容器來發(fā)布REST服務(wù)(要同時(shí)修改dubbo-demo-provider.xml,請看那個(gè)文件中的注釋),然后用6、7、8中的方式來訪問它。(當(dāng)然也可以在命令行直接mvn package,然后將生成的war部署到外面的tomcat中做測試)

11、如果想看服務(wù)監(jiān)控效果,或者避免demo拋出找不到監(jiān)控的異常警告,用IDE運(yùn)行/dubbo-simple/dubbo-simple-monitor/…/test目錄下的SimpleMonitor來啟動(dòng)監(jiān)控中心即可。

下載代碼,執(zhí)行下邊的命令:

mvn install -Dmaven.test.skip=true

1

但是經(jīng)測試如直接mvn install 的話會(huì)出現(xiàn)一系列的build 失敗信息。?

需要先修改dubbox根目錄下的pom.xml文件,注釋:

<!--<plugin>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<groupId>org.apache.maven.plugins</groupId>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<artifactId>maven-surefire-plugin</artifactId>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<configuration>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<testFailureIgnore>true</testFailureIgnore>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</configuration>-->

? ? ? ? ? ? ? ? ? ? <!--</plugin>-->

<!--<plugin>-->

? ? ? ? ? ? ? ? <!--<groupId>org.apache.maven.plugins</groupId>-->

? ? ? ? ? ? ? ? <!--<artifactId>maven-surefire-plugin</artifactId>-->

? ? ? ? ? ? ? ? <!--<version>${maven-surefire-plugin_version}</version>-->

? ? ? ? ? ? ? ? <!--<configuration>-->

? ? ? ? ? ? ? ? ? ? <!--<useSystemClassLoader>true</useSystemClassLoader>-->

? ? ? ? ? ? ? ? ? ? <!--<forkMode>once</forkMode>-->

? ? ? ? ? ? ? ? ? ? <!--<argLine>${argline}</argLine>-->

? ? ? ? ? ? ? ? ? ? <!--<systemProperties>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<!– common shared –>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>transporter</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${transporter}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>serialization</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${serialization}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<!– server side –>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>port</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${port}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>threadpool</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${threadpool}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>threads</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${threads}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>iothreads</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${iothreads}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<!– client side –>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>server</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${server}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>timeout</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${timeout}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>length</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${length}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>connections</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${connections}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>base</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${base}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>concurrent</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${concurrent}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>runs</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${runs}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>onerror</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${onerror}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? <!--</systemProperties>-->

? ? ? ? ? ? ? ? <!--</configuration>-->

? ? ? ? ? ? <!--</plugin>-->

<!--<plugin>-->

? ? ? ? ? ? ? ? <!--<groupId>org.apache.maven.plugins</groupId>-->

? ? ? ? ? ? ? ? <!--<artifactId>maven-surefire-plugin</artifactId>-->

? ? ? ? ? ? ? ? <!--<version>${maven-surefire-plugin_version}</version>-->

? ? ? ? ? ? ? ? <!--<configuration>-->

? ? ? ? ? ? ? ? ? ? <!--<useSystemClassLoader>true</useSystemClassLoader>-->

? ? ? ? ? ? ? ? ? ? <!--<forkMode>once</forkMode>-->

? ? ? ? ? ? ? ? ? ? <!--<argLine>${argline}</argLine>-->

? ? ? ? ? ? ? ? ? ? <!--<systemProperties>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<!– common shared –>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>transporter</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${transporter}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>serialization</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${serialization}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<!– server side –>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>port</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${port}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>threadpool</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${threadpool}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>threads</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${threads}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>iothreads</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${iothreads}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<!– client side –>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>server</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${server}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>timeout</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${timeout}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>length</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${length}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>connections</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${connections}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>base</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${base}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>concurrent</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${concurrent}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>runs</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${runs}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--<property>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<name>onerror</name>-->

? ? ? ? ? ? ? ? ? ? ? ? ? ? <!--<value>${onerror}</value>-->

? ? ? ? ? ? ? ? ? ? ? ? <!--</property>-->

? ? ? ? ? ? ? ? ? ? <!--</systemProperties>-->

? ? ? ? ? ? ? ? <!--</configuration>-->

? ? ? ? ? ? <!--</plugin>-->

等部分。

然后再運(yùn)行mvn install, 一般情況下有可能還是會(huì)build失敗。?

嘗試不同的網(wǎng)絡(luò)環(huán)境下build,總會(huì)成功的。

2.3 運(yùn)行dubbox-admin

在成功的build好dubbox源代碼之后,可以在IDE中運(yùn)行dubbo-demo項(xiàng)目中的例子。

在運(yùn)行之前需要:

1.啟動(dòng)zookeeper 執(zhí)行如下命令啟動(dòng):

bin/zkServer.sh start

2.測試連接zookeeper 執(zhí)行如下命令測試連接

bin/zkCli.sh -server ip:端口

如果發(fā)現(xiàn)你確實(shí)啟動(dòng)了zookeeper,但是連接不上的情況。請檢查防火墻設(shè)置。

3.部署dubbo-admin到你的tomcat

首先需要將dubbo-admin.war解壓后拷貝所有的文件到 webapp下的/ROOT目錄中(首先請刪除ROOT目錄中的所有文件)。 然后在部署目錄(即/ROOT目錄)下的WEB-INF目錄中找到dubbo.properties文件,打開該文件有如下配置項(xiàng):

dubbo.registry.address=zookeeper://121.40.97.224:2181

dubbo.admin.root.password=root

dubbo.admin.guest.password=guest

其中dubbo.registry.address項(xiàng)需要配置為注冊中心的地址和端口,也就是zookeeper的地址和端口

dubbo.admin.root.password為root管理用戶的登錄密碼。

dubbo.admin.guest.password為guest用戶的登錄密碼。

啟動(dòng)tomcat訪問dubbo-admin:?

http://127.0.0.1:8686 可以看到注冊中心的系統(tǒng)環(huán)境,系統(tǒng)狀態(tài)已經(jīng)供者情況

2.4 設(shè)置dubbo-demo中的配置,添加dubbo服務(wù)提供者

1.修改配置文件,設(shè)置注冊中心的地址為安裝好的zookeeper

<?xml version="1.0" encoding="UTF-8"?>

<!--

?- Copyright 1999-2011 Alibaba Group.

?-??

?- Licensed under the Apache License, Version 2.0 (the "License");

?- you may not use this file except in compliance with the License.

?- You may obtain a copy of the License at

?-??

?-? ? ? http://www.apache.org/licenses/LICENSE-2.0

?-??

?- Unless required by applicable law or agreed to in writing, software

?- distributed under the License is distributed on an "AS IS" BASIS,

?- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

?- See the License for the specific language governing permissions and

?- limitations under the License.

-->

<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-2.5.xsd

? ? http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

? ? <dubbo:application name="demo-provider" owner="programmer" organization="dubbox"/>

? ?<!--此處修改為安裝的注冊中心zookeeper地址-->

? ? <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

? ? <!--uncomment this if you want to test dubbo's monitor-->

? ? <!--<dubbo:monitor protocol="registry"/>-->

? ? <!-- here we demonstrate both annotation-based and xml-based configs -->

? ? <dubbo:annotation package="com.alibaba.dubbo.demo.user.facade" />

? ? <dubbo:protocol name="dubbo" serialization="kryo" optimizer="com.alibaba.dubbo.demo.SerializationOptimizerImpl"/>

? ? <!--<dubbo:protocol name="dubbo" serialization="fst" optimizer="com.alibaba.dubbo.demo.SerializationOptimizerImpl"/>-->

? ? <!--<dubbo:protocol name="dubbo" serialization="nativejava"/>-->

? ? <!--<dubbo:protocol name="dubbo" serialization="hessian2"/>-->

? ? <!--<dubbo:protocol name="dubbo" serialization="fastjson"/>-->

? ? <!--<dubbo:protocol name="dubbo" serialization="dubbo"/>-->

? ? <!--TODO according to the spring convention, we should use something like keep-alive-->

? ? <!-- use netty server -->

? ? <!--<dubbo:protocol name="rest" port="8888" keepalive="true" server="netty" iothreads="5" threads="100" contextpath="services"/>-->

? ? <!-- use tjws server -->

? ? <!--<dubbo:protocol name="rest" port="8888" server="tjws" contextpath="services"/>-->

? ? <!-- use tomcat server? 8888 -->

? ? ?<dubbo:protocol name="rest" port="8888" threads="500" contextpath="services" server="tomcat" accepts="500"

? ? ? ? ? ? ? ? ? ? extension="com.alibaba.dubbo.demo.extension.TraceInterceptor,

? ? ? ? ? ? ? ? ? ? com.alibaba.dubbo.demo.extension.TraceFilter,

? ? ? ? ? ? ? ? ? ? com.alibaba.dubbo.demo.extension.ClientTraceFilter,

? ? ? ? ? ? ? ? ? ? com.alibaba.dubbo.demo.extension.DynamicTraceBinding,

? ? ? ? ? ? ? ? ? ? com.alibaba.dubbo.demo.extension.CustomExceptionMapper,

? ? ? ? ? ? ? ? ? ? com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter"/>

? ? <!-- use the external tomcat or other server with the servlet approach; the port and contextpath must be exactly the same as those in external server -->

<!--? ? ?<dubbo:protocol name="rest" port="6080" contextpath="services" server="servlet"/> -->

<!--? ? ?<dubbo:protocol name="rest" server="servlet"/> -->

? ? <dubbo:protocol name="http" port="8889"/>

? ? <dubbo:protocol name="hessian" port="8890"/>

? ? <dubbo:protocol name="webservice" port="8892"/>

? ? <dubbo:service interface="com.alibaba.dubbo.demo.bid.BidService" ref="bidService"? protocol="dubbo"/>

? ? <!-- we add the group property since there's another annotation-configured service impl: com.alibaba.dubbo.demo.user.facade.AnnotationDrivenUserRestServiceImpl -->

? ? <dubbo:service interface="com.alibaba.dubbo.demo.user.UserService" ref="userService"? protocol="dubbo" group="xmlConfig"/>

? ? <dubbo:service interface="com.alibaba.dubbo.demo.user.facade.UserRestService" ref="userRestService"? protocol="rest" validation="true"/>

? ? <dubbo:service interface="com.alibaba.dubbo.demo.user.facade.AnotherUserRestService" ref="anotherUserRestService"? protocol="rest"? timeout="2000" connections="100" validation="true"/>

? ? <bean id="bidService" class="com.alibaba.dubbo.demo.bid.BidServiceImpl" />

? ? <bean id="userService" class="com.alibaba.dubbo.demo.user.UserServiceImpl" />

? ? <bean id="userRestService" class="com.alibaba.dubbo.demo.user.facade.UserRestServiceImpl">

? ? ? ? <property name="userService" ref="userService"/>

? ? </bean>

? ? <bean id="anotherUserRestService" class="com.alibaba.dubbo.demo.user.facade.AnotherUserRestServiceImpl">

? ? ? ? <property name="userService" ref="userService"/>

? ? </bean>

</beans>

2.5 部署運(yùn)行dubbo-demo-provider,dubbo-demo-consumer到測試服務(wù)器

將build之后的dubbo-demo-provider,dubbo-demo-consumer的target目錄打包上傳至需要部署的服務(wù)端。

解壓后在target目錄編寫啟動(dòng)腳本:

#!/bin/bash

java -classpath? /root/dubbox/demo/WEB-INF/classes:/root/dubbox/demo/WEB-INF/lib/*:/root/tomcat/apache-tomcat-7.0.65/lib/* com.alibaba.dubbo.demo.user.facade.DemoProvider >>dubbox.log 2>&1&

需要注意將所有依賴的jar包 類文件添加到classpath.

運(yùn)行該腳本,觀察dubbo-admin中的監(jiān)控情況

網(wǎng)站名稱:Dubbo詳細(xì)介紹與安裝使用過程
當(dāng)前URL:http://bm7419.com/article42/iihoec.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、動(dòng)態(tài)網(wǎng)站、網(wǎng)站設(shè)計(jì)、網(wǎng)站營銷、電子商務(wù)、自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)