dubbo+spring+zookeeper的集成入门实例

一、安装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/

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值