Spring整合Dubbo,使用zookeeper作爲註冊中心,進行遠程調用及負載均衡、自動失效轉移

1、Mavn依賴:

 

<span style="white-space:pre">			</span><!-- dubbo begin -->
			<dependency>
				<groupId>com.alibaba</groupId>
				<artifactId>dubbo</artifactId>
				<version>2.5.3</version>
				<exclusions>
					<exclusion>
						<artifactId>spring</artifactId>
						<groupId>org.springframework</groupId>
					</exclusion>
				</exclusions>
				<scope>runtime</scope>
			</dependency>
			<!-- dubbo end -->

			<!-- zookeeper begin -->
			<dependency>
				<groupId>org.apache.zookeeper</groupId>
				<artifactId>zookeeper</artifactId>
				<version>3.4.6</version>
				<exclusions>
					<exclusion>
						<groupId>org.slf4j</groupId>
						<artifactId>slf4j-log4j12</artifactId>
					</exclusion>
				</exclusions>
			</dependency>
			<dependency>
				<groupId>com.101tec</groupId>
				<artifactId>zkclient</artifactId>
				<version>0.4</version>
			</dependency>
			<!-- zookeeper end -->

 

2、定義服務端提供方和消費方的通信接口

 

IDispatch.java

 

package com.gaojiasoft.test.dubbo;

//服務接口,dubbo服務的提供方及消費方都需要使用
public interface IDispatch
{

	/**
	 * 有返回值,此時異步調用是收不到返回值的,需要在調用方增加回調接口獲取返回值。
	 * @param msg
	 * @return
	 */
    String dispatch(String msg);
    
    /**
     * 沒有返回值的,比較適合異步調用
     * @param msg
     */
    void noReturn(String msg);

}


3、在服務提供方實現具體的服務(在註銷代碼中,筆者視圖使用多線程來處理客戶端的請求,事實證明Dubbo中多此一舉,Dubbo是基於NIO的TCP通信,本身已經是線程池)

 

DispatchImpl.java

 

package com.gaojiasoft.test.dubbo.provider;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gaojiasoft.test.dubbo.IDispatch;

public class DispatchImpl implements IDispatch {
	public static final Logger log = LoggerFactory
			.getLogger(DispatchImpl.class);

	/**
	 *不需要使用多線程處理客戶端請求,因爲dubbo的服務端是NIO,內部含有多線程複用
	 */
	private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
			50, 150, 30L, TimeUnit.SECONDS,
			new LinkedBlockingQueue<Runnable>(),
			new BasicThreadFactory.Builder().daemon(true)
					.namingPattern("Dubbo-Provider-%d").build(),
			new ThreadPoolExecutor.CallerRunsPolicy());

	@Override
	public String dispatch(final String msg) {
//		String back = null;
//		Future<Object> future = executor.submit(new Callable<Object>() {
//			@Override
//			public Object call() throws Exception {
//				
//				log.debug("Server1 get msg:"+msg);
//				Thread.sleep(1);
//				return "SERVER 1 retrun:" + msg;
//				
//			}
//		});
//		try {
//			back = future.get().toString();
//		} catch (InterruptedException | ExecutionException e) {
//			e.printStackTrace();
//		}
//		return back;
		log.debug("Server1 get msg:"+msg);
		//Thread.sleep(1);
		return "SERVER 1 retrun:" + msg;
	}

	@Override
	public void noReturn(String msg) {
		
	}
}


4、服務提供方的Spring配置

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!-- dubbo服務提供方 -->
<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="Server-B" />
	<!-- 使用zookeeper對外暴露服務 -->
	<dubbo:registry protocol="zookeeper"
		address="192.168.62.155:2181,192.168.62.153:2181,192.168.62.154:2181" />

	<!-- 用dubbo協議在20880端口暴露服務 -->
	<!-- 提供服務的線程池固定數量爲100,iothreads配置CPU個數+1 -->
	<dubbo:protocol name="dubbo" port="20880" dispatcher="message"
		threadpool="fixed" threads="100" iothreads="3" />

	<!-- 聲明需要暴露的服務接口 及實現類-,版本號2.0.0,配置同樣版本號的消費者調用同樣版本號的生產者,executes="200"服務提供者線程池線程數, 
		loadbalance="leastactive"是負載服務端併發數量最小的,可選值random:隨機,roundrobin:輪詢,leastactive:最小併發 -->
	<dubbo:service interface="com.gaojiasoft.test.dubbo.IDispatch"
		ref="disPatchImpl" version="1.0.0" loadbalance="roundrobin" group="hs">
	</dubbo:service>

	<!-- 和本地bean一樣實現服務 -->
	<bean id="disPatchImpl" class="com.gaojiasoft.test.dubbo.provider.DispatchImpl" />
</beans>

 

 

 

關於配置文件的介紹:

1、<dubbo:protocol>中的dispatcher可選擇

0. all 所有消息都派發到線程池,包括請求,響應,連接事件,斷開事件,心跳等。
1. direct 所有消息都不派發到線程池,全部在IO線程上直接執行。
2. message 只有請求響應消息派發到線程池,其它連接斷開事件,心跳等消息,直接在IO線程上執行。
3. execution 只請求消息派發到線程池,不含響應,響應和其它連接斷開事件,心跳等消息,直接在IO線程上執行。
4. connection 在IO線程上,將連接斷開事件放入隊列,有序逐個執行,其它消息派發到線程池。

 

2、<dubbo:server>中的group適用於多個系統都有同樣名稱的服務,此時,通過分組加以區分,此時消費方配置同樣名稱分組的就會調用同樣名稱的消費方。

3、<dubbo:server>中的version使用一個服務有多個版本,此時服務端提供多,可以提供多個名稱同樣的方法,使用不通的版本號。例如:

 

<dubbo:service interface="com.gaojiasoft.test.dubbo.IDispatch"
		ref="<strong>disPatchImpl</strong>"<strong> version="1.0.0"</strong> loadbalance="roundrobin" group="hs">
</dubbo:service>
<dubbo:service interface="com.gaojiasoft.test.dubbo.IDispatch"
		ref="<strong>disPatchImpl</strong>" <strong>version="2.0.0"</strong> loadbalance="roundrobin" group="hs">
</dubbo:service>

可以看到,服務名稱一致,版本號不一直的服務被同時暴露,此時客戶端按照自己的需求調用不同的版本號。就使得整個平臺的可擴展性大大加強,非常使用整個平臺的向下兼容的能力。

 

 

 

5、服務提供方的啓動類

DubboTest.java

 

package com.gaojiasoft.test.dubbo;

import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DubboTest {

	private static ConfigurableApplicationContext contextProvider;

	private static ConfigurableApplicationContext contextConsumer;

	private Logger logger = LoggerFactory.getLogger("DubboTest");

	private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
			50, 150, 30L, TimeUnit.SECONDS,
			new LinkedBlockingQueue<Runnable>(),
			new BasicThreadFactory.Builder().daemon(true)
					.namingPattern("Dubbo-Consumer-%d").build(),
			new ThreadPoolExecutor.CallerRunsPolicy());

	@Test
	public void test() throws IOException, InterruptedException {

		// String []list = new
		// String[]{"classpath:conf/dubbo/spring-dubbo-provider.xml","classpath:conf/dubbo/spring-dubbo-consumer.xml"};
		// contextProvider = new ClassPathXmlApplicationContext(list,true,null);

		contextProvider = new ClassPathXmlApplicationContext(
				"classpath:conf/dubbo/spring-dubbo-provider.xml");

		while (true) {
			Thread.sleep(1);
		}

//		contextConsumer = new ClassPathXmlApplicationContext(
//				"classpath:conf/dubbo/spring-dubbo-consumer.xml");
//
//		IDispatch service = (IDispatch) contextConsumer.getBean("disPatcher");
//
//		int i = 1;
//		while (true) {
//			try {
//				// 多線程消費
//				mulitThreadConsumer(service, "" + i);
//			} catch (Exception e) {
//				logger.error("exception,dubbo provider error!");
//			}
//			Thread.sleep(1000);
//			i++;
//		}

	}

	/**
	 * 多線程消費者
	 * 
	 * @param keyvalue
	 */
	private void mulitThreadConsumer(final IDispatch service,
			final String message) {
		executor.execute(new Runnable() {
			@Override
			public void run() {
				try {
					String revice = service.dispatch(message);
					logger.debug("通過dubbo調用服務,返回的消息是:" + revice);
					Thread.sleep(1);

				} catch (Throwable th) {
					// 防禦性容錯,避免高併發下的一些問題
					logger.error("", th);
				}
			}
		});
	}
}


6、服務端消費方的Spring配置

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!-- dubbo服務消費方 -->
<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="Server-A" />

	<!-- 使用zookeeper註冊中心暴露服務地址 -->
	<dubbo:registry protocol="zookeeper" address="192.168.62.155:2181,192.168.62.153:2181,192.168.62.154:2181" />
	
	<!-- 生成遠程服務代理,與服務提供者建立3個TCP連接,並採用異步調用(非阻塞) -->
	<dubbo:reference id="disPatcher" connections="3"
		interface="com.gaojiasoft.test.dubbo.IDispatch" version="1.0.0" sent="false"
		async="true" group="hs">
		<!-- active是消費方請求線程池線程數,可針對不同的方法聲明不同的線程數-->
		<dubbo:method name="dispatch" return="false" actives="50"></dubbo:method>
	</dubbo:reference>
</beans>

 

 

7、服務消費方的啓動類

DubboConsumerStart.java

 

package com.study.dubbo.consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gaojiasoft.test.dubbo.IDispatch;

public class DubboConsumerStart
{
    public static final Logger log = LoggerFactory.getLogger(DubboConsumerStart.class);

    public static void main(String[] args) throws Exception
    {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("conf/spring-dubbo-consumer.xml");
        context.start();

        IDispatch service = (IDispatch) context.getBean("dispatcher");
        int i =1;
        while(true)
        {
        	try
        	{
        		String revice = service.dispatch(""+i);
                log.debug("通過dubbo調用服務,返回的消息是:" + revice);
                Thread.sleep(1);
                i++;
        	}catch(Exception e)
        	{
        		log.debug("調用異常:" + e.getClass().getName());
        	}
        }
        
       // System.in.read(); //爲保證服務一直開着,利用輸入流的阻塞來模擬 
    }
}

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章