網上關於dubbo的資料其實已經不少了,尤其是還有一個比較全面的官方文檔教程。
但是正所謂知易行難,很多事不動動手,就總不知道里邊的一些細節。
雖然早就想學一下dubbo,但是奈何需要學的東西太多,於是就以“工作爲主導”的出發點,先學了其他技術。
這次,也是基於上邊的出發點,我們某個項目需要重構成dubbo的項目,於是便正好從dubbo基礎環境搭建開始學一下,並寫一篇筆記備忘。
這篇筆記大概會包含如下一些內容:
1、搭建過程記錄
2、遇到的問題和解決辦法記錄,這一點會在搭建過程記錄的同時進行說明,不另外指出
整個過程基本如下:
zookeeper註冊中心
註冊中心的理解
由於之前學習過springcloud微服務,所以對於zookeeper註冊中心的理解,我覺得還是比較容易的。具體的理解可以參考當時寫的springcloud的註冊中心那篇文章: http://blog.csdn.net/tuzongxun/article/details/72650100
比較明顯的不同是,這裏的zookeeper需要下載安裝一個zookeeper軟件。
zookeeper安裝
我在安裝的時候主要是參考了“小寶鴿”的博客,他寫的很是詳細,所以我覺得沒有必要在重複造輪子,只需要記住在哪裏可以查到參考資料。他關於zookeeper安裝的博客地址如下:
http://blog.csdn.net/u013142781/article/details/50395650
dubbo管理平臺
由於管理平臺與業務邏輯本身沒有關係,所以我沒有深入瞭解,也是直接參考“小寶鴿”的博客:
http://blog.csdn.net/u013142781/article/details/50396621
dubbo服務者
創建項目
根據目前的主流,我這裏是在eclipse中創建了一個maven管理的web項目。
基礎依賴
項目基礎依賴主要參考dubbo官方指導文檔的說明http://dubbo.io/books/dubbo-user-book/dependencies.html
按照這個文檔上所說,需要包含如下一些依賴組件,分別是:
dubbo.jar
spring.jar
log4j.jar
commons-logging.jar
javassist.jar
netty.jar
在實際導入的時候會發現,dubbo.jar已經依賴了spring.jar和netty.jar,這個版本也是根據導入的dubbo.jar的版本來定的。
爲了避免衝突,也爲了使用自己想要的版本的spring和netty,於是在導入dubbo.jar時需要把這兩個先進行排除配置,之後的pom.xml中依賴包的配置基本如下:
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.15</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.jboss.netty</groupId> <artifactId>netty</artifactId> <version>3.2.5.Final</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>org.jboss.netty</groupId> <artifactId>netty</artifactId> </exclusion> </exclusions> </dependency>
spring配置
dubbo本身就整合了spring,因此spring的配置是必不可少的,這裏也是使用最簡單的配置,文件頭就先省略:
<context:property-placeholder location="classpath:config.properties" /> <import resource="spring-dubbo-provider.xml" />
config.properties配置
配置dubbo服務,需要指定zookeeper註冊中心的地址,以及使用dubbo暴露服務的端口等,這些配置配在config.properties文件中:
dubbo.zookepper.address=127.0.0.1:2181 dubbo.provider.port=29880
dubbo配置
要把我們的項目作爲一個服務註冊到zookeeper註冊中心,就需要進行相應的配置,配置如下:
<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:application name="dubboServerDemo-pro"/> <!-- 註冊中心配置,file值爲application name加實例名 --> <dubbo:registry protocol="zookeeper" address="${dubbo.zookepper.address}" file="dubboServerDemo-pro-1.cache"/> <!-- 用dubbo協議在20880端口暴露服務,dubbo訪問日誌輸出到應用日誌 --> <dubbo:protocol name="dubbo" port="${dubbo.provider.port}" accesslog="true"/> <!-- 聲明需要暴露的服務接口 超時時間90分鐘,超時不重試--> <dubbo:service interface="dubboServerTest.DubboServerService" ref="dubboServiceTest" cluster="failfast" timeout="5400000" /> <!-- 和本地bean一樣實現服務 --> <bean id="dubboServiceTest" class="dubboServerTest.DubboServerServiceImpl" /> </beans>
dubbo具體服務接口和實現
dubbo的具體服務接口和實現就是很普通的java接口和類,如下:
package dubboServerTest; public interface DubboServerService { public void sayHello(); }
package dubboServerTest; public class DubboServerServiceImpl implements DubboServerService { @Override public void sayHello() { System.out.println("dubbo測試"); } }
web.xml配置
spring.xml文件需要被加載,可以用java代碼加載,也可以用其他方式,我這裏就選擇使用web.xml的配置來加載,web.xml配置如下:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list>
問題說明
按理說,照上邊的做法程序應該是可以運行,並且可以再管理平臺中顯示出服務者的,但是實際上我啓動後卻拋出瞭如下異常:
java.lang.NoClassDefFoundError: org/I0Itec/zkclient/exception/ZkNoNodeException
原因是少了zookeeper的依賴包,需要在pom.xml中補上如下的依賴配置:
<dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.10</version> </dependency>
消費者
項目搭建
消費者的項目搭建其實和服務者差不多,區別在於dubbo的配置略有區別,消費者的配置大致如下:
<!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 --> <dubbo:application name="consumer-of-helloworld-app" /> <!-- 使用multicast廣播註冊中心暴露發現服務地址 --> <dubbo:registry address="${dubbo.zookepper.address}" /> <!-- 生成遠程服務代理,可以和本地bean一樣使用demoService --> <dubbo:reference id="demoService" interface="dubboServerTest.DubboServerService" />
同樣的,這裏的也需要指定註冊中心的地址,也是配置在config.properties中:
dubbo.zookepper.address=zookeeper://127.0.0.1:2181
需要注意的是,這裏配置的zookeeper註冊中心地址的寫法,和服務中心配置的寫法也略有不同。
接口聲明
消費端,需要一個和服務端一樣的接口,但是不用實現這個接口。這裏的做法實際上和webservice接口比較類似,像cxf、xfire、hessian都差不多。
服務調用
在消費端可以直接調用上邊聲明的接口的抽象方法,而實際上運行的就是服務端的具體實現,調用處的代碼如下:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import dubboServerTest1.DubboServerService; public class MyController { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "classpath:spring.xml"); DubboServerService dubboServerService = (DubboServerService) applicationContext .getBean("demoService"); dubboServerService.sayHello(); } }
問題說明
消費者這裏相對比較簡單,但是除了說對於zookeeper註冊中心地址的配置處有細節需要注意外,對於接口的聲明也需要特別注意。
爲了驗證是否和webservice一樣的,消費端接口包括包名在內都必須和服務端一樣,我在聲明接口時特意使用了不一樣的包名,使得實際的類內容以及在dubbo配置文件中的配置如下:
package dubboServerTest1; public interface DubboServerService { public void sayHello(); }
<dubbo:reference id="demoService" interface="dubboServerTest1.DubboServerService" />
然後運行main方法的時候,就會拋出如下異常:
Caused by: java.lang.IllegalStateException: Failed to check the status of the service dubboServerTest1.DubboServerService. No provider available for the service
由此也就證明,消費端的接口聲明,包括包名在內,都必須和服務端一模一樣。針對這個問題,有一種推薦的做法,就是把這個接口類打包,讓服務端和消費端公用。