Nacos注册、配置中心整合Dubbo远程调用

Nacos注册、配置中心整合Dubbo远程调用(文末含demo代码地址)

  • 背景
  • 开发环境
  • 搭建父项目
    • 创建项目
    • 声明依赖
  • 建立子模块
    • 创建order子模块
  • 抽取公共的代码结构
  • 编写order模块中的Dubbo相关代码
    • 编写common模块中OrderService的实现类
    • 编写配置文件
  • 启动Nacos
  • 进入Nacos管理界面创建配置文件
  • 将order模块注册到Naocs
  • 编写服务消费者模块
    • 调用order服务的接口
    • 编写配置文件
  • 启动main模块,将其注册到Nacos中
  • 测试
  • 源码地址

背景

Nacos作为阿里巴巴技术栈中的一员,目前在应用得也是比较广泛。作为一个后起之秀,它相较于老一辈得Eureka注册中心也有很多优势。Dubbo同样也是阿里巴巴技术栈的成员,那么它和Nacos相结合无疑是非常不错的选择。最近看了很多帖子,要么是很老的,要么就是参考价值不大,索性,我自己写一个,Nacos和Dubbo整合使用的坑还是比较多。

开发环境

类别 名称及版本
开发工具 IntelliJ IDEA 2021.2.3
MAVEN Apache Maven 3.8.1
JAVA JDK1.8.291
SpringBoot 2.4.2
SpringCloudAlibaba 2021.1
MyBatis 2.1.4
Dubbo 2.7.8
Nacos 2.0.3

请注意,以上版本(SpringBoot、SpringCloudAlibaba 、Dubbo)对应关系完全按照官方推荐来搭配的。版本差异或许会导致其他问题,但如果您有其他需求,请您查看官方文档以获取相关信息
Nacos注册、配置中心整合Dubbo远程调用_第1张图片
Nacos注册、配置中心整合Dubbo远程调用_第2张图片

版本参考地址

搭建父项目

通常来讲,我们会使用聚合的方式来统一项目中的依赖,直接在父项目中声明好依赖,并管理好版本,在子项目中我们就不再需要写版本号了,方便统一。

创建项目

我们的父项目事实上只有一个功能,那就是帮我们管理依赖版本,所以我们可以删除其不要的结构,让他看起来干净些。项目结构如下(项目名我只是随便写的一个):
Nacos注册、配置中心整合Dubbo远程调用_第3张图片

声明依赖

创建好父项目之后,我们接下来把需要用到的各种依赖申明在父项目的POM的中dependencyManagement标签中,以方便我们管理其版本,使其版本统一。这里您需要注意以下packaging标签我们要声明为pom,因为我们这个只是作为父项目出现。如果您非常熟悉SpringBoot项目,那么您肯定知道spring-boot-maven-plugin插件,一般的SpringBoot项目导入spring-boot-maven-plugin插件的方式一般是这样的:

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

但是现在我们不能这么声明了,不然会报错,其他相关信息您可以参考官方文档。您应该以如下方式申明(版本我声明在properties中作为一个变量出现的,和SpringBoot的版本号一致):

<build>
   <plugins>
       <plugin>
           <groupId>org.springframework.bootgroupId>
           <artifactId>spring-boot-maven-pluginartifactId>
           <version>${spring-boot-dependencies.version}version>
           <executions>
               <execution>
                   <goals>
                       <goal>repackagegoal>
                   goals>
               execution>
           executions>
       plugin>
   plugins>
build>

完整的POM文件代码如下:


<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.0modelVersion>
    <packaging>pompackaging>

    <groupId>com.fenzhichuanmei.sunflowergroupId>
    <artifactId>sunflowerartifactId>
    <version>1.0-SNAPSHOTversion>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
        <mybatis.spring-boot.version>2.1.4mybatis.spring-boot.version>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <spring-boot-dependencies.version>2.4.2spring-boot-dependencies.version>
        <dubbo-spring-boot-starter.version>2.7.8dubbo-spring-boot-starter.version>
        <spring-cloud-alibaba-dependencies.version>2021.1spring-cloud-alibaba-dependencies.version>
    properties>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>${spring-boot-dependencies.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>

            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                <version>${spring-cloud-alibaba-dependencies.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>

            <dependency>
                <groupId>org.mybatis.spring.bootgroupId>
                <artifactId>mybatis-spring-boot-starterartifactId>
                <version>${mybatis.spring-boot.version}version>
            dependency>

            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubbo-spring-boot-starterartifactId>
                <version>${dubbo-spring-boot-starter.version}version>
            dependency>
        dependencies>
    dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
                <version>${spring-boot-dependencies.version}version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackagegoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>

project>

我这里没有通过继承的方式导入SpringBoot依赖,而是在dependencyManagement标签中声明,所有用到的依赖的版本号我在上方的properties用变量方式声明以方便管理。

建立子模块

创建order子模块

我创建了一个名为order的子模块继承sunflower项目,项目结构如下:
Nacos注册、配置中心整合Dubbo远程调用_第4张图片
order子模块POM文件内容如下


<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">
    <parent>
        <artifactId>sunflowerartifactId>
        <groupId>com.fenzhichuanmei.sunflowergroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>orderartifactId>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
    properties>

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

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <scope>runtimescope>
        dependency>

        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
        dependency>

        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>

        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
        dependency>

        <dependency>
            <groupId>org.apache.dubbogroupId>
            <artifactId>dubbo-spring-boot-starterartifactId>
        dependency>

        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-lang3artifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-configuration-processorartifactId>
            <optional>trueoptional>
        dependency>
    dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.xmlinclude>
                includes>
            resource>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes>
                    <include>**/*.yamlinclude>
                includes>
            resource>
        resources>
    build>
project>

因为我需要用到mybatis,且我将mybatis的mapper.xml文件放在了类路径中和接口同包,所以我在POM中配置了将类路径下的.xml文件导出,您可以根据您自己的情况具体问题具体分析。

抽取公共的代码结构

Dubbo官方推荐我们将接口、异常等抽取到一个模块中,然后其他模块通过导入的形式引用公共的结构。所以我根据官方的推荐,建立了一个common模块,其结构如下:
Nacos注册、配置中心整合Dubbo远程调用_第5张图片
这里您需要注意,如果您的实体类要在Dubbo调用的过程中传递,那么您需要将这个实体类实现java.io.Serializable接口,否则会报错。举个例子:

package com.fenzhichuanmei.sunflower.common.order.pojo;

import com.fenzhichuanmei.sunflower.common.pojo.BasePojo;
import lombok.Data;

import java.io.Serializable;

/**
 * @Author: DaiYi
 * @Email: [email protected]
 * @CreateTime: 2021-11-09 9:48
 * @Description: an entity class that encapsulates order information
 */

@Data
public class Order extends BasePojo implements Serializable {

    private String goodsId;

    private String orderNumber;

    private String phoneNumber;

    private String recipient;

    private String province;

    private String city;

    private String county;

    private String town;

    private String detail;

}

我在公共模块中抽取出了OrderService接口,并声明了两个方法:

package com.fenzhichuanmei.sunflower.common.order.service;

import com.fenzhichuanmei.sunflower.common.order.pojo.Order;
import com.fenzhichuanmei.sunflower.common.response.ResponseBody;

/**
 * @Author: DaiYi
 * @Email: [email protected]
 * @CreateTime: 2021-11-09 10:20
 * @Description:
 */

public interface OrderService {

    ResponseBody queryOrders(Order order);

    ResponseBody queryOrderProperties();

}
 

编写order模块中的Dubbo相关代码

编写common模块中OrderService的实现类

我们刚刚把OrderService抽取到公共模块common中,但是其实现类我们应该在具体的模块中编写,代码如下(其他代码请下载源码参考):

package com.fenzhichuanmei.sunflower.order.service.impl;

import com.fenzhichuanmei.sunflower.common.order.pojo.Order;
import com.fenzhichuanmei.sunflower.common.order.service.OrderService;
import com.fenzhichuanmei.sunflower.common.response.ResponseBody;
import com.fenzhichuanmei.sunflower.common.response.StatusCode;
import com.fenzhichuanmei.sunflower.order.config.OrderProperties;
import com.fenzhichuanmei.sunflower.order.mapper.OrderMapper;
import org.apache.dubbo.config.annotation.DubboService;

import javax.annotation.Resource;
import java.util.List;

/**
 * @Author: DaiYi
 * @Email: [email protected]
 * @CreateTime: 2021-11-09 10:21
 * @Description:
 */

@DubboService
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderProperties orderProperties;

    @Override
    public ResponseBody queryOrders(Order order) {
        List<Order> orders = orderMapper.queryOrders(order);
        return ResponseBody.of(StatusCode.SUCCESS, orders);
    }

    @Override
    public ResponseBody queryOrderProperties() {
        return ResponseBody.of(StatusCode.SUCCESS, orderProperties.getPdfCourierOrderStorageLocation());
    }

}

@DubboService注解表示这是一个Dubbo组件,他将可以被其他服务所调用,声明了这个注解之后可以不用再声明Spring框架的注解了。

编写配置文件

注意:这个配置文件应该叫bootstrap.yaml,因为他将作为引导的配置文件,而非传统的application.yaml

server:
  port: 8081
spring:
  application:
    name: order
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        namespace: 2c1bff8e-b530-4c7e-9dda-4d404371c605
      config:
        namespace: ${spring.cloud.nacos.discovery.namespace}
        group: configuration-files
        file-extension: yaml

dubbo:
  scan:
    base-packages: com.fenzhichuanmei.sunflower.order.service.impl
  protocols:
    dubbo:
      name: dubbo
      port: 20881
  registry:
    address: nacos://${spring.cloud.nacos.server-addr}
    parameters:
      namespace: ${spring.cloud.nacos.discovery.namespace}

启动Nacos

这里我使用单机启动,没有使用集群,windows中命令为:startup.cmd -m standalone
Nacos注册、配置中心整合Dubbo远程调用_第6张图片

进入Nacos管理界面创建配置文件

因为我们刚刚写了config相关的配置,所以我们现在要去nacos中新建一个配置文件与其对应。
给大家展示一下我引用了远程配置的类:

package com.fenzhichuanmei.sunflower.order.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.io.Serializable;

/**
 * @Author: DaiYi
 * @Email: [email protected]
 * @CreateTime: 2021-11-09 15:56
 * @Description: order module configuration class
 */

@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "order")
public class OrderProperties implements Serializable {
    /**
     * note that this path must be a directory
     */
    private String pdfCourierOrderStorageLocation;
}

@RefreshScope注解表示这个类中的配置信息将会动态刷新

我在nacos的配置列表中创建了一个名为order,group为configuration-files的配置文件与我上面的配置相对应。配置项如下:

order:
    pdf-courier-order-storage-location: https://www.baidu.com

将order模块注册到Naocs

启动order模块的主启动类,将其注册到nacos。这里一定要注意,在高版本中,bootstrap.yaml默认不会先加载。通常有两个解决方法,一个是导入相关jar包,另一个就是配置参数了,通常我选择后者。所以我在order模块的VM options配置项中添加了-Dspring.cloud.bootstrap.enabled=true配置:
Nacos注册、配置中心整合Dubbo远程调用_第7张图片

启动之后,在服务列表中即可看到我们的服务和暴露出来的接口
Nacos注册、配置中心整合Dubbo远程调用_第8张图片

编写服务消费者模块

我编写了一个叫main的模块,作为服务消费者。其POM文件内容如下:


<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">
    <parent>
        <artifactId>sunflowerartifactId>
        <groupId>com.fenzhichuanmei.sunflowergroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>mainartifactId>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
        <sunflower.common.version>1.0-SNAPSHOTsunflower.common.version>
    properties>

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

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>

        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>

        <dependency>
            <groupId>org.apache.dubbogroupId>
            <artifactId>dubbo-spring-boot-starterartifactId>
        dependency>

        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-lang3artifactId>
        dependency>

        <dependency>
            <groupId>com.fenzhichuanmei.sunflowergroupId>
            <artifactId>commonartifactId>
            <version>${sunflower.common.version}version>
        dependency>
    dependencies>

project>

项目结构如下:
Nacos注册、配置中心整合Dubbo远程调用_第9张图片

调用order服务的接口

package com.fenzhichuanmei.sunflower.main.controller;

import com.fenzhichuanmei.sunflower.common.order.pojo.Order;
import com.fenzhichuanmei.sunflower.common.order.service.OrderService;
import com.fenzhichuanmei.sunflower.common.response.ResponseBody;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: DaiYi
 * @Email: [email protected]
 * @CreateTime: 2021-11-09 15:00
 * @Description:
 */

@RestController
public class OrderController {

    @DubboReference(interfaceClass = OrderService.class)
    protected OrderService orderService;

    @PostMapping("/queryOrders")
    public ResponseBody queryOrders(@RequestBody Order order) {
        return orderService.queryOrders(order);
    }

    @PostMapping("/queryOrderProperties")
    public ResponseBody queryOrderProperties() {
        return orderService.queryOrderProperties();
    }

}

@DubboReference注解表示引用一个服务,可以用interfaceClass属性指定这个接口

特别注意: 在nacos中,不同命名空间(namespace)之间的服务是不可以相互调用的,而且,即使在同一个namespace下,但是不在同一个组中也是不可以相互调用的,他们之间是隔离起来的
相关帖子:https://developer.aliyun.com/ask/317473 传送门

编写配置文件

server:
  port: 8082
  servlet:
    context-path: /order
spring:
  application:
    name: main
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        namespace: 2c1bff8e-b530-4c7e-9dda-4d404371c605
dubbo:
  protocols:
    dubbo:
      name: dubbo
      port: 20882
  registry:
    address: nacos://${spring.cloud.nacos.server-addr}
    parameters:
      namespace: ${spring.cloud.nacos.discovery.namespace}

启动main模块,将其注册到Nacos中

Nacos注册、配置中心整合Dubbo远程调用_第10张图片

测试

Nacos注册、配置中心整合Dubbo远程调用_第11张图片

源码地址

gitee:https://gitee.com/daiyi-personal/sunflower.git

你可能感兴趣的:(java,maven,spring,cloud,dubbo,spring,cloud,alibaba)