1. 程式人生 > >dubbo+zookeeper+springmvc搭建例項教程

dubbo+zookeeper+springmvc搭建例項教程

這裡引用官方文件的一張圖片,來簡單說明各個節點的角色職責
流程

節點角色說明:

  • Provider: 暴露服務的服務提供方。
  • Consumer: 呼叫遠端服務的服務消費方。
  • Registry: 服務註冊與發現的註冊中心。
  • Monitor: 統計服務的呼叫次調和呼叫時間的監控中心。
  • Container: 服務執行容器。

一、本篇概述

本篇分兩個部分。
第一,搭建好provider和consumer後,使用Main方法阻塞來模擬,不涉及到SpringMVC。
第二,搭建後,使用SpringMVC進行注入呼叫遠端服務介面。

二、準備工作

框架版本:

  • tomcat8,jdk7
  • dubbo-admin-2.4.1.war 這是dubbo管理war包,修改war直接扔到tomcat跑就可以了。
  • zookeeper-3.4.5 本例項使用zookeeper作為註冊中心,其實還能使用其他的,這裡不詳細講解。

2.1 搭建zookeeper(我這裡是window環境)

2.2 部署dubbo-admin-2.4.1.war

直接放到tomcat的webapp資料夾下,執行tomcat。

  • 配置資訊都在WEB-INF/dubbo.properties下,管理員賬號密碼都是root,zookeeper的地址等。

三、建立提供者provider工程(使用maven構建)

dubbo.provider專案結構如下圖:
專案構建

匯入依賴,pom.xml如下:

<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.soecode</groupId> <artifactId>dubbo.provider</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>dubbo.provider Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- Logger日誌 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency> <!-- dubbo --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.4.10</version> </dependency> <!-- zookeeper --> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.3.4</version> </dependency> <!-- zkclient 用於訪問zookeeper --> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.3</version> </dependency> </dependencies> <build> <finalName>dubbo.provider</finalName> </build> </project>

在service包下建立介面HelloService.java

package com.soecode.dubbo.service;

public interface HelloService {

    /**
     * say hello
     * @param name
     * @return
     */
    public String sayHello(String name);
}

在Service.impl下實現介面HelloServiceImpl.java

package com.soecode.dubbo.service.impl;

import org.springframework.stereotype.Service;

import com.soecode.dubbo.service.HelloService;

@Service("helloServiceImpl")
public class HelloServiceImpl implements HelloService {

    public String sayHello(String name) {
        return "hello,"+name+"!";
    }

}

接下來填寫dubbo-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:context="http://www.springframework.org/schema/context"
    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://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 註解包掃描位置: 因為這裡的實現類使用註解的方式 -->
    <context:component-scan base-package="com.soecode.dubbo.*" />

    <!-- 接入dubbo的應用程式名稱 -->
    <dubbo:application name="demo-provider" />

    <!-- 註冊倉庫地址:zookeeper元件,192.168.61.128:2181 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />

    <!-- 用dubbo協議在20880埠暴露服務 -->  
    <dubbo:protocol name="dubbo" port="20880" />

    <!-- 
            宣告需要暴露的服務介面,
            請注意ref屬性中指定的HelloService介面實現類,它並沒有在xml檔案中定義,而是使用註解的方式在class中定義
     -->
    <dubbo:service interface="com.soecode.dubbo.service.HelloService" ref="helloServiceImpl"/>  
</beans>

到此服務介面已經定義好,接下來要通過main方法讀取配置檔案,來達到zookeeper服務註冊的效果。

建立ProviderApp.java

package com.soecode.dubbo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 服務提供者示例
 * @author antgan
 * @date 2017/1/12
 *
 */
public class ProviderApp {

    public static void main(String[] args) throws Exception {
        //讀取配置檔案
        new ClassPathXmlApplicationContext(new String[]{"dubbo-provider.xml"});
        System.out.println("provider服務已註冊");
        //使執行緒阻塞
        System.in.read();
    }

}

執行ProviderApp,即可。

如何校驗是否成功註冊?進入dubbo-admin,點選單欄上的提供者,如下圖就註冊成功了,成功暴露介面。
提供者

四、建立消費者consumer專案

dubbo.consumer專案結構
專案構建

引入依賴,pom.xml如下

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.soecode</groupId>
    <artifactId>dubbo.consumer</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo.consumer Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <!-- log4j日誌 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>

        <!-- dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.4.10</version>
        </dependency>

        <!-- zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.3.4</version>
        </dependency>

        <!-- zkclient -->
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.3</version>
        </dependency>

        <!-- 引用dubbo.provider -->
        <dependency>
            <groupId>com.soecode</groupId>
            <artifactId>dubbo.provider</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>


        <!-- SpringMVC -->
        <!-- spring web依賴 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <!--3: Servlet web 相關依賴 -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.5.4</version>
        </dependency>

    </dependencies>
    <build>
        <finalName>dubbo.consumer</finalName>
    </build>
</project>

配置dubbo-consumer.xml,向zookeeper註冊介面(有點像存根)

<?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:application name="demo-consumer" />

    <!-- 註冊倉庫地址:zookeeper元件,192.168.61.128:2181 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />

    <!-- 引用的服務,那個interface一定是一個被引入到DUBBO倉庫的介面定義 -->
    <dubbo:reference id="helloService" interface="com.soecode.dubbo.service.HelloService"/>  
</beans>

建立ConsumerApp.java,執行測試

package com.soecode.dubbo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.soecode.dubbo.service.HelloService;

/**
 * 消費者示例
 * @author antgan
 * @date 2017/1/12
 *
 */
public class ConsumerApp {
    public static void main(String[] args) throws Exception {
        //讀取配置檔案
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"dubbo-consumer.xml"});
        //獲取在zookeeper註冊的服務介面
        HelloService helloService = (HelloService)context.getBean("helloService");
        //呼叫介面
        System.out.println("HelloService = " + helloService.sayHello("ant"));
        //不讓控制檯消失,按任意鍵結束
        System.in.read();
    }
}

執行結果:
執行結果

我們也可以在dubbo-admin上看一下,如下
消費者

至此,已經完成了第一部分在main方法模擬呼叫遠端介面

五、consumer引入SpringMVC

dubbo.consumer引入springMVC,pom.xml 新增以下jar包:

        <!-- SpringMVC -->
        <!-- spring web依賴 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <!--3: Servlet web 相關依賴 -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.5.4</version>
        </dependency>

在resource資料夾下建立spring-web.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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    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">

    <!-- 配置SpringMVC -->
    <!-- 1:開啟SpringMVC註解模式 -->
    <!-- 簡化配置:
    1)自動註冊DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter 
    2) 提供一系列:資料繫結,數字和日期的format等功能,支援xml,json讀寫-->
    <mvc:annotation-driven/>

    <!--2: 靜態資源配置 
    1) 加入靜態資源的處理,如js,gif,png
    2)允許使用"/"處理
    -->
    <mvc:default-servlet-handler/>

    <!-- 3: 配置jsp 顯示ViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />  <!-- 字首 -->
        <property name="suffix" value=".jsp" />   <!-- 字尾 -->
    </bean>

    <!-- 4: 掃描web相關的bean -->
    <context:component-scan base-package="com.soecode.dubbo.web"/>

</beans>

修改web.xml,使其執行時載入配置檔案。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>dubbo.consumer</display-name>

    <!-- 載入dubbo-consumer.xml -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/dubbo-consumer.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!-- 配置DispatcherServlet -->
    <servlet>
        <servlet-name>dubbo.consumer-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 載入spring-web.xml -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-web.xml</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dubbo.consumer-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

dubbo.web包下建立HelloController.java

package com.soecode.dubbo.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.soecode.dubbo.service.HelloService;

@Controller
@RequestMapping("hello")
public class HelloController {

    /**
     * 注入遠端介面
     */
    @Autowired
    private HelloService helloService;

    /**
     * 呼叫遠端介面,返回index.jsp頁面
     * @param model
     * @return
     */
    @RequestMapping("index")
    public String index(Model model){
        model.addAttribute("str", helloService.sayHello("ant"));
        return "index";
    }
}

幾個坑,你可能會遇到:

一、遇到這個報錯

java.lang.NullPointerException
    at org.springframework.core.SerializableTypeWrapper$TypeProxyInvocationHandler.invoke(SerializableTypeWrapper.java:239)

解決辦法:這是因為spring的jar包衝突,dubbo自帶一個2.x.x版本的spring。pom修改如下:

        <!-- dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.4.10</version>
            <exclusions>
                <exclusion>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

二、其他都做好了,就是無法啟動。
解決方法:可以嘗試provider打包成jar,consumer引入。

三、無法讀取dubbo的配置檔案
解決方法:下載dubbo.xsd,手動新增xsd。具體方法可以參考。解決:dubbo找不到dubbo.xsd報錯

最後,一起進步一起學習吧!