spring+zookeeper+dubbo使用例項

yingxian_Fei發表於2017-04-30

本文實現一個spring+zookeeper+dubbo的使用例項,本文實現建立一個簡單的服務介面。然後在dubbo的服務端實現該介面並向zookeeper伺服器進行註冊,客戶端向zookeeper伺服器訂閱該介面並使用。zookeeper和dubbo的環境搭建和測試可以查閱http://blog.csdn.net/smilefyx/article/details/70992427部落格中的簡述。

個人覺得比較好的博文推薦如下:

http://www.cnblogs.com/linjiqin/p/5859153.html

http://doc.okbase.net/congcong68/archive/112508.html

http://dubbo.io/User+Guide-zh.htm

1、新增主要依賴

新增dubbo的依賴,相關依賴如下:

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>dubbo</artifactId>
			<version>2.5.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
			<version>3.4.6</version>
		</dependency>
		<dependency>
			<groupId>com.github.sgroschupf</groupId>
			<artifactId>zkclient</artifactId>
			<version>0.1</version>
		</dependency>

2、建立測試伺服器介面

建立如下介面,該介面中僅定義了一個hello的方法。原始碼如下:

package cn.landsem.dubbo;

public interface ITestRegistryService {
	public String hello(String name);
}

3、伺服器端實現介面

在伺服器端對第一步中定義的介面進行實現,原始碼如下:

package cn.landsem.dubbo.impl;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import cn.landsem.dubbo.ITestRegistryService;

@Service("testRegistryServiceImpl")
public class TestRegistryServiceImpl implements ITestRegistryService{
	Logger logger = Logger.getLogger(TestRegistryServiceImpl.class);

	public String hello(String name) {
		logger.info("Say hello.");
		return "hello!"+name;
	}

}

4、建立dubbo用於註冊或訂閱的配置檔案

4.1、伺服器端向zookeeper註冊配置的配置

在類路徑下建立applicationContext-dubbo.xml配置用於配置dubbo服務,該檔案的原始碼如下:

<?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:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="  
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
		">
	<!-- 提供方應用名稱資訊,這個相當於起一個名字,我們dubbo管理頁面比較清晰是哪個應用暴露出來的 -->
	<dubbo:application name="dubbo_provider"></dubbo:application>
	<!-- 使用zookeeper註冊中心暴露服務地址 -->
	<dubbo:registry address="zookeeper://127.0.0.1:2181"  check="false" subscribe="false" register=""></dubbo:registry>
	<!-- 要暴露的服務介面 -->
	<dubbo:service interface="cn.landsem.dubbo.ITestRegistryService" ref="testRegistryServiceImpl" />
</beans>

4.2、客戶端向zookeeper訂閱服務的配置

在類路徑下建立clienttest-applicationContext-dubbo.xml配置檔案用於配置工程向zookeeper伺服器訂閱步驟2中註冊的服務,該檔案的原始碼如下:

<?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:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="  
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
		">
	<!-- 提供方應用名稱資訊,這個相當於起一個名字,我們dubbo管理頁面比較清晰是哪個應用暴露出來的 -->
	<dubbo:application name="dubbo_customer"></dubbo:application>
	<!-- 使用zookeeper註冊中心暴露服務地址 -->
	<dubbo:registry address="zookeeper://127.0.0.1:2181"  check="false" subscribe="true" register="false"></dubbo:registry>
	<dubbo:reference id="testRegistryServiceImpl" interface="cn.landsem.dubbo.ITestRegistryService" />
</beans>

5、建立基於java的配置類

5.1、伺服器端java配置類

建立一個基於java註解的配置類用於載入xml的配置檔案以及實現服務的自動掃描和bean建立。如下為伺服器端配置類的原始碼:

package cn.landsem.configuration;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.ImportResource;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan({"cn.landsem.dubbo.impl"})
@ImportResource("classpath:applicationContext-dubbo.xml")
public class RootConfiguration {

}

5.2、客戶端java配置類

建立一個基於java註解的配置類用於載入客戶端的xml配置檔案,如下為配置類的原始碼:

package cn.landsem.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.ImportResource;

@Configuration
@EnableAspectJAutoProxy
@ImportResource("classpath:clienttest-applicationContext-dubbo.xml")
public class TestConfiguration {

}

6、建立測試類

6.1、服務端註冊服務測試類

這裡建立兩個類,一個基類用於載入相關配置(伺服器端使用RootConfiguration的java配置類),一個子類繼承基類的配置並完成具體的測試工作,方便後續擴充套件。基類的原始碼如下:

package cn.landsem.tester;

import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import cn.landsem.configuration.RootConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(classes = {RootConfiguration.class})   
@WebAppConfiguration 
public class BaseServerTest {
}

子類的功能比較簡單,就是啟動後等待使用者輸入任意鍵後退出。原始碼如下:

package cn.landsem.tester.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.log4j.Logger;
import org.junit.Test;

import cn.landsem.tester.BaseServerTest;

public class ServerTester extends BaseServerTest{
	private Logger logger = Logger.getLogger(BaseServerTest.class);
	
	@Test
	public void test() {
        try {
    		logger.info("Wait input to exit.");
            InputStreamReader is_reader = new InputStreamReader(System.in);          	
			new BufferedReader(is_reader).readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

6.2、客戶端測試類

客戶端也分開為測試的基類和子類,基類負責載入配置(客戶端載入TestConfiguration的配置類),原始碼如下:

package cn.landsem.tester;

import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import cn.landsem.configuration.TestConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(classes = {TestConfiguration.class})   
@WebAppConfiguration 
public class BaseClientTest {

}

子類的功能也比較簡單,注入服務,然後做一個回聲測試,然後等待使用者輸入任意鍵後退出測試。相關原始碼如下:

package cn.landsem.tester.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import cn.landsem.dubbo.ITestRegistryService;
import cn.landsem.tester.BaseClientTest;

import com.alibaba.dubbo.rpc.service.EchoService;

public class ClientTester extends BaseClientTest{
	private Logger logger = Logger.getLogger(ClientTester.class);
	
	@Autowired
	private ITestRegistryService mDubboTest;
	
	@Test
	public void test() {
        try {
        	logger.info("dubbo server="+mDubboTest.hello("123"));
        	EchoService echoService = (EchoService) mDubboTest;
        	Object status = echoService.$echo("OK");
        	assert(status.equals("OK"));
    		logger.info("Wait input to exit.");
            InputStreamReader is_reader = new InputStreamReader(System.in);          	
			new BufferedReader(is_reader).readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}

}

7、執行測試

首先執行測試工程錢需先執行zookeeper工程,如果需要檢視後臺,需要執行dubbo-admin的web工程,具體見http://blog.csdn.net/smilefyx/article/details/70992427部落格中的簡述。

7.1、執行伺服器端測試

點選ServerTester的java檔案,右鍵Run As -- JUnit Test執行測試。執行成功後輸出如下:


此時登入dubbo-admin管理介面,可以檢視到已經成功註冊了一個服務到zookeeper中。如圖


7.2、執行客戶端測試

點選ClientTester的java類並奕junit測試執行,執行成功後輸出如下:


8、常見問題

(1)、找不到dubbo.xsd檔案

https://github.com/alibaba/dubbo下載原始碼,然後在其中搜尋找到dubbo.xsd的檔案,將該檔案拷貝到工程類目錄下,開啟myeclipse--window---preference,搜尋xml,並找到XML Catalog選項。點選右側的Add按鈕,輸入key為如下內容

http://code.alibabatech.com/schema/dubbo/dubbo.xsd
並在Location中選擇剛才下載匯入的dubbo.xsd檔案,之後確定,clean工程即可。這裡由於我將該檔案放到工程的類路徑下,所以我選擇workspace來定位到該檔案。

(2)、org.apache.catalina.LifecycleException

在整合Spring工程後,啟動工程你可能會遇到工程向你丟擲org.apache.catalina.LifecycleException的異常並停止執行。最終引發異常的原因可能時找不到Spring某個jar包中的某個方法。如類似下面的錯誤:

嚴重: ContainerBase.addChild: start: 
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/aop]]
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162)
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
	at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1260)
	at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:2002)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationAwareOrderComparator.sort(Ljava/util/List;)V
	at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:167)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5623)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
	... 10 more
五月 11, 2017 3:14:35 下午 org.apache.catalina.startup.HostConfig deployDirectory
嚴重: Error deploying web application directory D:\tomcat\apache-tomcat-7_0_75_1\webapps\aop
java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/aop]]
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:903)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
	at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1260)
	at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:2002)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:744)
百度上可能會告訴你時web.xml配置不對、jdk版本不對、jar包依賴不全等等。但是我要告訴你的是,可能時spring的jar包衝突導致的。我們閱讀dubbo的幫助文件http://dubbo.io/User+Guide-zh.htm中的預設依賴頁面,你會看到dubbo預設會依賴一個spring的jar包,而這個jar包版本可能比你工程中用到的其他spring版本要低,所有就造成了你在其他地方希望引用新spring特性的時候引用不到從而報錯。解決辦法是排除dubbo的預設jar包依賴,修改dubbo的配置,修改後配置如下:

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>dubbo</artifactId>
			<version>2.5.3</version>
		        <exclusions>
				<exclusion>
					<artifactId>spring</artifactId>
					<groupId>org.springframework</groupId>
				</exclusion>
			</exclusions>
		</dependency>
修改完成後更新maven的依賴,然後再執行工程,如果還在報錯再去嘗試其他方法。

注意:由於上傳的原始碼只是使用了簡單的spring特性,而且上傳時候沒考慮到這個問題,所有並沒有做dubbo自帶spring的排除。希望下載原始碼的人看到這裡的提醒。

9、原始碼下載

本例項原始碼可以從如下地址進行下載http://download.csdn.net/detail/yxtouch/9829802

相關文章