一、安裝zookeeper
可以參考用兩臺物理機搭建Storm集羣裏面對zookeeper的安裝。需要注意的是必須確保zookeeper正常啓動,也就是必須監聽端口2181。可以使用如下命令:
sudo lsof -i:2181
$ZK_HOME/bin/zookeeper.out可以看到綁定了端口,這個文件會記錄訪問zookeeper的日誌。如果出現問題,可以到$ZK_HOME/zookeeper.out,如果提示沒有nohup java這個命令,則是zkServer.sh裏面的JAVA變量沒找到,需要進行修改,將JAVA改爲實際的路徑:
二、下載dubbo啓動控制檯
從git下載dubbo並安裝相關jar包到本地倉庫,可以發現dubbo目錄下有很多個子模塊,其實可以不安裝的。主要是爲了編譯dubbo-admin這個子模塊,並運行。
git clone https://github.com/alibaba/dubbo.git
cd dubbo
mvn clean install -Dmaven.test.skip
先啓動zookeeper,然後跳到dubbo-admin下運行:
cd dubbo-admin
mvn jetty:run -Ddubbo.registry.address=zookeeper://127.0.0.1:2181
這時會啓動dubbo的控制檯,在瀏覽器訪問:http://localhost:8080,然後輸入用戶名和密碼,均爲root,即可看到如下界面:
在admin控制檯中可以查看相關的提供者的服務(接口),是否沒有提供者,以及消費者的消費情況等等。
三、dubbo使用實例
dubbo是一個遠程過程調度(RPC)框架,使用zookeeper作爲服務的註冊中心,以及消費者通過訂閱獲取服務的相關地址及端口號。首先定義一個統一的接口api,供服務提供者和消費者使用。服務提供者實現這個接口api,並向zookeeper註冊IP和端口,同時使用dubbo協議開發服務的接口實例,運行起來,供消費者調用。消費者同樣使用dubbo協議,只需要幾行配置就可以調用遠程接口,獲取數據。
3.1 統一的api
新建一個dubbo_api_demo1項目,使用maven,定義了兩個接口。單獨定義一個項目是爲了解耦提供者和消費者,同時統一一樣的接口,實現者和使用者最後沒有異議。可以將這個項目作爲依賴導入提供者和消費者的pom中。
HelloService:
package com.jessin.dubbo;
/**
* Created by jessin on 17-7-22.
*/
public interface HelloService {
String sayHello(String name);
String sayGoodBye(String name);
}
CalculateService:
package com.jessin.dubbo;
/**
* Created by jessin on 17-7-22.
*/
public interface CalculateService {
int add(int a, int b);
int subtract(int a, int b);
}
項目結構如下:
由於有其他項目依賴這個項目,可以將這個項目打成jar,安裝到本地(mvn install)或者部署到私服(mvn deploy),以便其他人可以使用。
3.2 服務提供者的實現
同樣新建一個項目,對兩個接口進行實現,如下:
HelloServiceImpl:
package com.jessin.dubbo.impl;
import com.jessin.dubbo.HelloService;
/**
* Created by jessin on 17-7-22.
*/
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello, " + name;
}
public String sayGoodBye(String name) {
return "goodbye, " + name;
}
}
CalculateServiceImpl:
package com.jessin.dubbo.impl;
import com.jessin.dubbo.CalculateService;
/**
* Created by jessin on 17-7-22.
*/
public class CalculateServiceImpl implements CalculateService {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
這個項目就不需要自己在定義api接口了,直接引用api模塊作爲依賴即可,同時必須引入dubbo的依賴,貌似dubbo只能在spring下使用?具體的pom如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jessin.dubbo_provider</groupId>
<artifactId>dubbo_provider_demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>dubbo_provider</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.1.4.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
</properties>
<dependencies>
<!-- 引用本地的其他項目或模塊,版本保持跟該模塊一致,保持最新-->
<dependency>
<groupId>com.jessin.dubbo</groupId>
<artifactId>dubbo_api_demo1</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- 引入Spring依賴,主要是dubbo命名空間在spring配置文件中 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-asm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring end -->
<!-- log -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- 必須引入dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
</dependency>
<!-- 必須引入zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!-- zookeeper -->
<!--<dependency>-->
<!--<groupId>org.apache.zookeeper</groupId>-->
<!--<artifactId>zookeeper</artifactId>-->
<!--<version>3.3.6</version>-->
<!--</dependency>-->
</dependencies>
<build>
<finalName>dubbo_provider_demo</finalName>
<plugins>
<!-- 非多個資源配置 start-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.1</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
<encoding>UTF-8</encoding>
<failOnError>false</failOnError>
</configuration>
</plugin>
<!-- 非多個資源配置 end-->
<!--
在target目錄下將classes文件打成jar,並填寫MANIFEST的入口和類路徑爲lib
所有的依賴均被放到lib下
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.jessin.dubbo.main.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
值得注意的是,這個項目的pom文件使用mvn package後,會在target目錄下生成lib目錄,存放pom依賴,並將本項目打成可以運行的jar,因爲在MAINFEST.MF指定了入口類和類路徑lib,具體的運行命令如下:
java -jar dubbo_provider_demo.jar
該入口類爲Main,必須運行起來:
package com.jessin.dubbo.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
/**
* Created by jessin on 17-7-22.
*/
public class Main {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring/app_provider.xml"});
context.start();
System.out.println("按任意鍵退出");
System.in.read();
}
}
可以看到,其實就是加載了spring的配置文件,然後進入IO阻塞。該文件的內容如下:
spring/app_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="dubbo_provider" />
<!-- zookeeper客戶端,連接zookeeper的地址及協議-->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" />
<!-- 服務提供者綁定的IP及端口號,使用dubbo協議,提供給調用者-->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 提供一個bean實例 -->
<!-- 和本地bean一樣實現服務 -->
<bean id="helloService" class="com.jessin.dubbo.impl.HelloServiceImpl" />
<!-- 提供接口的實現-->
<dubbo:service interface="com.jessin.dubbo.HelloService" ref="helloService" />
<!-- 和本地bean一樣實現服務 -->
<bean id="calculateService" class="com.jessin.dubbo.impl.CalculateServiceImpl" />
<!-- 提供接口的實現-->
<dubbo:service interface="com.jessin.dubbo.CalculateService" ref="calculateService" />
</beans>
可以看到,該配置文件註冊了兩個服務的實現,生成了兩個接口類實例並託管給spring容器,並且將具體的服務IP及端口通過zookeeper的2181端口註冊到zookeeper上。
項目結構如下:
3.3 消費者的實現
同樣使用Maven構建一個新的項目,這裏是基於spring的web項目,同樣引入api依賴。
web.xml如下,分別使用了spring/app_consumer.xml、spring/mvc_consumer.xml作爲業務層和web層的配置文件,訪問鏈接前綴爲/dubbo/consumer/。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 字符編碼過濾器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 服務層和業務層 -->
<!-- 指定持久層和業務層的配置文件:在類路徑下,初始化業務層Spring容器,也是父容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring/app_consumer.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- web層-->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/spring/mvc_consumer.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<!--不能使用/*,但可以使用/crud/*,使用*.do會把後綴名去掉-->
<url-pattern>/dubbo/consumer/*</url-pattern>
</servlet-mapping>
</web-app>
查看spring/app_consumer.xml,可以看到客戶端如何引入遠程實例,獲取遠程數據:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 -->
<dubbo:application name="dubbo_consumer"/>
<!-- 向zookeeper獲取服務註冊的地址,同時獲取rpc生成bean實例註冊到spring中 -->
<dubbo:registry address="zookeeper://localhost:2181"/>
<!-- 直接請求兩個遠程接口實例-->
<dubbo:reference id="helloService" interface="com.jessin.dubbo.HelloService" />
<dubbo:reference id="calculateService" interface="com.jessin.dubbo.CalculateService"/>
</beans>
這時兩個接口實例helloService和calculateService就可以直接使用了,如注入到controller中。看下spring/mvc_consumer.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 掃描類包,將標註Spring註解的類自動轉化Bean,同時完成Bean的注入 -->
<context:component-scan base-package="com.jessin.dubbo.controller"/>
<!-- 需要這一個配置,使得下面的json配置有效-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 完成JSON格式數據的自動轉換-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>
</beans>
spring會掃描controller包下的文件的註解,完成controller的生成,以及service的自動注入,這裏提供了一個HelloController:
package com.jessin.dubbo.controller;
import com.jessin.dubbo.CalculateService;
import com.jessin.dubbo.HelloService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
/**
* Created by jessin on 17-7-22.
*/
@Controller
public class HelloController {
// 從配置文件中注入
@Resource
private HelloService helloService;
@Resource
private CalculateService calculateService;
@RequestMapping(value = "/hello", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String sayHello(@RequestParam(required = false, defaultValue = "Tom") String name){
return helloService.sayHello(name);
}
@RequestMapping(value = "/goodbye", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String sayGoodbye(@RequestParam(required = false, defaultValue = "Tom") String name){
return helloService.sayHello(name);
}
@RequestMapping(value = "/add", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String add(@RequestParam("a") int a, @RequestParam("b")int b){
int sum = calculateService.add(a, b);
return String.format("%d + %d = %d", a, b, sum);
}
@RequestMapping(value = "/subtract", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String subtract(@RequestParam("a") int a, @RequestParam("b") int b){
int diff = calculateService.subtract(a, b);
return String.format("%d - %d = %d", a, b, diff);
}
}
顯然,當我們訪問/dubbo/consumer/hello時,將在前端得到一個json字符串,具體配置可以看mvc_consumer.xml中的RequestMappingHandlerAdapter注入,同時必須注入RequestMappingHandlerMapping實例,除了和服務提供端一樣引入dubbo、zkclient、spring依賴外,還需引入如下json依賴:
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>
最後在pom.xml下引入maven的jetty插件,可以直接通過如下命令運行起來:
mvn tomcat7:run
具體的pom中jetty配置如下:
<build>
<finalName>dubbo_consumer_demo</finalName>
<plugins>
<!-- Tomcat插件,使用jetty運行 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 注意端口是8081 -->
<port>8081</port>
<path>/</path>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
項目結構如下:
四、程序運行和測試
由於服務提供者和消費者均依賴於zookeeper這裏先將zookeeper啓動,然後啓動服務提供者,最後啓動消費者,並通過瀏覽器調用。
啓動zookeeper
啓動dubbo_provider_demo
啓動dubbo_consumer_demo
訪問瀏覽器
啓動控制檯
訪問http://localhost:8080/index.html,如下:
輸入用戶名root,密碼root,得到:
搜索HelloService,得到提供者正在運行的信息,在localhost:20880進行監聽。
再點擊消費者,可以得到消費情況:
點擊應用,可以得到兩個應用,與dubbo:application對應:
附件:本文源碼下載
參考文獻:
http://blog.csdn.net/congcong68/article/details/41113239
http://mushanshitiancai.github.io/2016/07/29/java/%E6%90%AD%E5%BB%BAdubbo-zookeeper-spring%E7%8E%AF%E5%A2%83-%E7%8E%AF%E5%A2%83%E7%AF%87/
http://mushanshitiancai.github.io/2016/07/29/java/%E6%90%AD%E5%BB%BAdubbo-zookeeper-spring%E7%8E%AF%E5%A2%83-%E7%BC%96%E7%A0%81%E7%AF%87/