一步一步搭建 springboot-2.1.3+dubbo-2.7.1 项目

7,247 阅读10分钟

写在前面

作为一个php程序员转java开发,一直停留在 hello world 的水平上,最近由于一时发热想试一下 dubbo 的新版本,但是 github 找了一遍又一遍都没有看到有demo,而官方给出的例子复制出来是没办法单独运行的,不是这个错就那个错,反正搞了一下午也没有解决。

于是决定自己试一试,填补一下搜索引擎空白。

开发环境

  • Spring Boot: 2.1.3.RELEASE
  • Dubbo: 2.7.1-SNAPSHOT
  • 开发工具:Mac IDEA

实战

废话少说,show me the code !

创建项目

现在开始用 IDEA 创建一个没有代码的 Spring boot maven 工程

选择 Spring Initializr 初始化项目

创建模块

创建 api 模块,即 interface 定义

创建 service 模块,即 provider 服务提供者

创建 web 模块,即 consumer 服务消费者

创建完这个模块之后来执行个 mvn clean install 试一下,结果报错了

[INFO] skip non existing resourceDirectory /Users/jeftom/workspace/java/dubbo-sample/dubbo-demo/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ dubbo-demo ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ dubbo-demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/jeftom/workspace/java/dubbo-sample/dubbo-demo/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ dubbo-demo ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ dubbo-demo ---
[INFO] No tests to run.
[INFO] 
[INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ dubbo-demo ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: /Users/jeftom/workspace/java/dubbo-sample/dubbo-demo/target/dubbo-demo-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.1.3.RELEASE:repackage (repackage) @ dubbo-demo ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.142 s
[INFO] Finished at: 2019-03-23T22:05:17+08:00
[INFO] Final Memory: 24M/395M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.3.RELEASE:repackage (repackage) on project dubbo-demo: Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.1.3.RELEASE:repackage failed: Unable to find main class -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException

找到 Tests 单元测试用例,加上 @Ignore 注释跳转先,剩下的先不管那么多了。

主模块配置

在根模块的 pom.xml 里增加

<packaging>pom</packaging>

<modules>
    <module>dubbo-demo-api</module>
    <module>dubbo-demo-service</module>
    <module>dubbo-demo-web</module>
</modules>

打包插件也需要调整一下,因为根模板没有使用到 spring boot 的 main 启动类,换成 maven 的打包插件才能继续下去。

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
            <plugin>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.7.1</version>
            </plugin>
            <plugin>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>3.0.0</version>
            </plugin>
        </plugins>
    </pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-site-plugin</artifactId>
            <configuration>
                <locales>en,fr</locales>
            </configuration>
        </plugin>
    </plugins>

    <!-- 这里要把 spring boot 自带的 spring-boot-maven-plugin 插件换成 maven-site-plugin,否则 mvn 打包会报错 -->
    <!-- <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins> -->
</build>

在其它三个子模块的 pom.xml 增加

<packaging>jar</packaging>

修改完成之后,执行 mvn clean install 试一下

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] dubbo-demo-api ..................................... SUCCESS [  5.428 s]
[INFO] dubbo-demo-service ................................. SUCCESS [  1.299 s]
[INFO] dubbo-demo-web ..................................... SUCCESS [  3.195 s]
[INFO] dubbo-demo ......................................... SUCCESS [  0.039 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.258 s
[INFO] Finished at: 2019-03-23T22:21:46+08:00
[INFO] Final Memory: 50M/525M
[INFO] ------------------------------------------------------------------------

离成功又近了一步,虽然还没有任何代码,但是起码几个模块已经 build 通过了。

dubbo-demo-api 模块

删除 dubbo-demo-api 里的启动类,因为这个模块主要保存的是接口的定义。

增加 DemoApi 接口类

package com.example.dubbo.demo.api;

/**
 * Demo 接口定义
 *
 * @author jeftom
 * @date 2019-03-23 22:35
 * @since 1.0.0
 */
public interface DemoApi {
   String sayHello(String name);
}

pom 文件打包插件改为:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>
    </plugins>
</build>

dubbo-demo-service 模块

这个模块主要的功能是接口的实现,业务功能的服务提供者。

先来看看该模块的 pom.xml 配置:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.dubbo</groupId>
    <artifactId>dubbo-demo-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>dubbo-demo-service</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- dubbo provider 启动不成功的主要问题在这里,没有添加 spring-boot-starter-web 依赖,所以启动日志里一直没有显示 “o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8087 (http)” 这行日志输出 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 这个是定义的接口包,在 provider 和 consumer 都需要引用的 -->
        <dependency>
            <groupId>com.example.dubbo</groupId>
            <artifactId>dubbo-demo-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!-- 新增 dubbo 依赖 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.1-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

重点要说这里,因为创建模块的时候没有勾选 web 依赖,所以 pom 里只有 spring-boot-starter,并没包含 spring-boot-starter-web 的依赖,启动服务的时候总是完成之后就退出掉,mvn install 也是正常的,百思不得其姐,这里花费了我几个小时的时间。增加完 spring-boot-starter-web 依赖之后,启动日志里就能看到 tomcat 的日志了

o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8087 (http)

现在我们来创建一个 DemoApiImpl 类,对 sayHello 方法实现响应:

package com.example.dubbo.demo.service.impl;

import com.example.dubbo.demo.api.DemoApi;
import org.apache.dubbo.config.annotation.Service;

/**
 * demo 实现类
 *
 * @author jeftom
 * @date 2019-03-23 23:04
 * @since 1.0.0
 */
@Service
public class DemoApiImpl implements DemoApi {
   /**
    * 实现 sayHello 接口
    *
    * @param name
    * @return
    */
   @Override
   public String sayHello(String name) {
      return "Hello, " + name + " (from Spring Boot with dubbo-2.7.1)";
   }
}

DubboDemoServiceApplication 启动类需要增加 dubbo 配置注解:

package com.example.dubbo.demo.service;

import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 增加了 EnableDubboConfig 和 DubboComponentScan 的注解,启动时自动扫描
 *
 */
@EnableDubboConfig
@DubboComponentScan("com.example.dubbo.demo.service.impl")
@SpringBootApplication
public class DubboDemoServiceApplication {

   public static void main(String[] args) {
      SpringApplication.run(DubboDemoServiceApplication.class, args);
   }

}

增加 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:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="
        http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- 定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字 -->
    <dubbo:application name="${dubbo.application.name}" owner="jeftom" organization="jeftom"  />

    <!-- 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper-->
    <dubbo:registry id="zookeeper-registry" protocol="${dubbo.registry.protocol}" address="${dubbo.registry.address}" />

    <!-- dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="${dubbo.protocol.name}" port="${dubbo.protocol.port}" accesslog="dubbo-access.log"/>
    <dubbo:provider retries="0" timeout="30000"/>
    <dubbo:monitor protocol="registry"/>

    <!-- 使用 dubbo 协议实现定义好的 Service Api 接口-->
    <dubbo:service interface="com.example.dubbo.demo.api.DemoApi" ref="DemoApiImpl" retries="0" timeout="60000" />
</beans>

spring 项目的 application.properties 配置文件:

spring.config.name=application

# spring 的环境配置
spring.profiles.active=dev
# 服务启动端口,即内置 tomcat 启动时占用的端口
server.port=8087

#dubbo config
#应用定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字,方便辨识
dubbo.application.name=dubbo-demo-service
#应用所属者
dubbo.application.owner=jeftom
#应用所属组织
dubbo.application.organization=jeftom

# 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper
# 注册中心id
dubbo.registry.id=zookeeper-registry
# 注册中心协议
dubbo.registry.protocol=zookeeper
# 注册中心地址
dubbo.registry.address=zookeeper.tencus.com:2181

# dubbo协议在20880端口暴露服务
# 协议名称
dubbo.protocol.name=dubbo
# 协议端口
dubbo.protocol.port=20880
# 协议访问log
dubbo.protocol.accesslog=dubbo-access.log
# 重试次数
dubbo.provider.retries=0
# 超时时间
dubbo.provider.timeout=3000
# 注册监控中心
dubbo.monitor.protocol=registry

至此,我们的服务提供者已经可以正常启动了,通过 dubbo-admin 可以看到服务已经注册到 zookeeper 里。

dubbo-demo-web 模块

这个模块是 dubbo 的 consumer 服务,用于消费提供者提供的服务,服务启动后会与提供者进行连接,完成服务调用。

pom.xml 配置文件:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.dubbo</groupId>
    <artifactId>dubbo-demo-web</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>dubbo-demo-web</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- dubbo provider 启动不成功的主要问题在这里,没有添加 spring-boot-starter-web 依赖,所以启动日志里一直没有显示 “o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8087 (http)” 这行日志输出 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 这个是定义的接口包,在 provider 和 consumer 都需要引用的 -->
        <dependency>
            <groupId>com.example.dubbo</groupId>
            <artifactId>dubbo-demo-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!-- 新增 dubbo 依赖 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.1-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

spring 应用的 application.properties 配置:

spring.config.name=application

# spring 的环境配置
spring.profiles.active=dev
# 服务启动端口,即内置 tomcat 启动时占用的端口
server.port=8088

# Qos 运维监控
dubbo.application.qosEnable=true
dubbo.application.qosPort=33333
dubbo.application.qosAcceptForeignIp=false

# dubbo config
# 应用定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字,方便辨识
dubbo.application.name=dubbo-demo-service
# 应用所属者
dubbo.application.owner=jeftom
# 应用所属组织
dubbo.application.organization=jeftom

# 使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper
# 注册中心id
dubbo.registry.id=zookeeper-registry
# 注册中心协议
dubbo.registry.protocol=zookeeper
# 注册中心地址
dubbo.registry.address=zookeeper.tencus.com:2181

# dubbo协议在20880端口暴露服务
# 协议名称
dubbo.protocol.name=dubbo
# 协议端口
dubbo.protocol.port=20880
# 协议访问log
dubbo.protocol.accesslog=dubbo-access.log
# 重试次数
dubbo.provider.retries=0
# 超时时间
dubbo.provider.timeout=3000
# 注册监控中心
dubbo.monitor.protocol=registry

如果同一台机器上同时启动两个服务,会导致 Qos 端口冲突:

main [server.Server] 102 [ERROR]  [DUBBO] qos-server can not bind localhost:22222

DubboDemoWebApplication 消费者的启动类增加以下两行注解:

@EnableDubboConfig
@DubboComponentScan("com.example.dubbo.demo.web.service")

分别创建 DemoService 服务类和 DemoController 控制器,

DemoService.java 类

package com.example.dubbo.demo.web.service;

import com.example.dubbo.demo.api.DemoApi;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * 消费者服务层
 *
 * @author jeftom
 * @date 2019-03-24 00:49
 * @since 1.0.0
 */
@Service
public class DemoService {
   private static final Logger LOGGER = LoggerFactory.getLogger(DemoService.class);

   @Reference
   private DemoApi demoApi;

   public String sayHello(String name) {
      return demoApi.sayHello(name);
   }
}

DemoController.java 控制器类

package com.example.dubbo.demo.web.controller;

import com.example.dubbo.demo.web.service.DemoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * demo 控制器
 *
 * @author jeftom
 * @date 2019-03-24 00:51
 * @since 1.0.0
 */
@RestController
@RequestMapping("/demo")
public class DemoController {
   private static Logger logger = LoggerFactory.getLogger(DemoController.class);

   @Autowired
   private DemoService demoService;

   /**
    * 测试方法,浏览器访问 /demo/index 可以看到响应结果了
    *
    * @return
    */
   @RequestMapping(value = "/index", method = RequestMethod.GET)
   @ResponseBody
   public String index() {
      return demoService.sayHello("dubbo");
   }
}

好了,现在可以重新 reimport 和 mvn install 一下看看有没有报错,如果没有报了,启动 service 和 web 两个服务,然后打开浏览器访问,撸了这么久,终于出来了。

结语

以上是是我花了两天才调试通的 dubbo-2.7.1 版本调用服务的demo,如果你也正准备使用 dubbo 尝试新版本来做服务化开发,希望本文对你有一点点的帮助,非常感谢** 阿里团队**开源出来这么优秀的RPC解决方案。