Nacos registration and configuration center integrate Dubbo remote call

background

As a member of Alibaba's technology stack, Nacos is currently widely used. As a rising star, it also has many advantages over the older Eureka registry. Dubbo is also a member of Alibaba's technology stack, so it is undoubtedly a very good choice to combine it with Nacos. I have read a lot of posts recently, either they are very old, or they have little reference value. Simply, I write one myself. There are still many pitfalls in the integration of Nacos and Dubbo.

development environment

category name and version
development tools 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

Please note that the corresponding relationship between the above versions (SpringBoot, SpringCloudAlibaba, Dubbo) is completely matched according to the official recommendation. Version differences may cause other problems, but if you have other needs, please check the official documentation for relevant information
insert image description here
insert image description here

Version reference address

Build the parent project

Generally speaking, we will use the aggregation method to unify the dependencies in the project, directly declare the dependencies in the parent project, and manage the version, so that we no longer need to write the version number in the sub-project, which is convenient for unification.

create project

Our parent project actually has only one function, which is to help us manage dependency versions, so we can delete its unnecessary structure to make it look cleaner. The project structure is as follows (I just wrote the project name casually):
insert image description here

Declare dependencies

After creating the parent project, we then declare the various dependencies that we need to use in the middle dependencyManagementtag of the parent project's POM, so that we can manage its version and make it uniform. Here you need to pay attention to the following packagingtags we want to declare as pom, because ours only appears as a parent project. If you are very familiar with the SpringBoot project, then you must know spring-boot-maven-pluginthe plug-in. The general SpringBoot project imports the spring-boot-maven-plugin plug-in generally like this:

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

But now we can't declare it like this, otherwise an error will be reported. For other related information, you can refer to the official document. You should declare it in the following way (I declared the version as a variable in properties, which is consistent with the version number of SpringBoot):

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

The complete POM file code is as follows:

<?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>
    <packaging>pom</packaging>

    <groupId>com.fenzhichuanmei.sunflower</groupId>
    <artifactId>sunflower</artifactId>
    <version>1.0-SNAPSHOT</version>

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


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot-dependencies.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba-dependencies.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring-boot.version}</version>
            </dependency>

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

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

</project>

I did not import SpringBoot dependencies through inheritance, but declared them in the dependencyManagement tag. The version numbers of all the dependencies I used were declared as variables in the properties above for easy management.

build submodule

Create order submodule

I created a submodule named order to inherit the sunflower project. The project structure is as follows:
insert image description here
The content of the order submodule POM file is as follows

<?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">
    <parent>
        <artifactId>sunflower</artifactId>
        <groupId>com.fenzhichuanmei.sunflower</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order</artifactId>

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

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.yaml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

Because I need to use mybatis, and I put the mapper.xml file of mybatis in the same package as the interface in the class path, so I configured in the POM to export the .xml file under the class path, you can according to your own Specific analysis of specific issues.

Extract common code structures

Dubbo officially recommends that we extract interfaces, exceptions, etc. into a module, and then other modules refer to the public structure through import. So I built a common module according to the official recommendation, and its structure is as follows:
common module structure
Here you need to pay attention, if your entity class is to be passed during the Dubbo call, then you need to implement the java.io.Serializableinterface for this entity class, otherwise an error will be reported. for example:

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;

}

I extracted the OrderService interface in the public module and declared two methods:

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();

}
 

Write Dubbo-related code in the order module

Write the implementation class of OrderService in the common module

We have just extracted OrderService into the public module common, but we should write its implementation class in a specific module. The code is as follows (please download the source code for reference for other codes):

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());
    }

}

@DubboServiceThe annotation indicates that this is a Dubbo component that can be called by other services. After declaring this annotation, you don't need to declare the annotations of the Spring framework.

Write a configuration file

NOTE: This config file should be called bootstrap.yamlbecause it will serve as the bootstrap config file, not the traditionalapplication.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}

Start Nacos

Here I use a single machine to start, without using a cluster, the command in windows is: startup.cmd -m standalone.
insert image description here

Enter the Nacos management interface to create a configuration file

Because we just wrote the configuration related to config, we are now going to create a new configuration file in nacos to correspond to it.
Let me show you the class that I referenced the remote configuration:

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;
}

@RefreshScopeThe annotation indicates that the configuration information in this class will be refreshed dynamically

I created a configuration file ordernamed in the nacos configuration list, and the group configuration-filesis corresponding to my configuration above. The configuration items are as follows:

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

Register the order module with Naocs

Start the main startup class of the order module and register it with nacos. It must be noted here that in higher versions, bootstrap.yamlit will not be loaded first by default. There are usually two solutions, one is to import related jar packages, and the other is to configure parameters. Usually I choose the latter. So I added -Dspring.cloud.bootstrap.enabled=trueconfiguration to the VM options configuration item of the order module:
insert image description here

After starting, we can see our service and exposed interface in the service list
insert image description here

Write a service consumer module

I wrote a module called main as a service consumer. The content of its POM file is as follows:

<?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">
    <parent>
        <artifactId>sunflower</artifactId>
        <groupId>com.fenzhichuanmei.sunflower</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>main</artifactId>

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

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

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

</project>

The project structure is as follows:
insert image description here

Interface to call order service

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();
    }

}

@DubboReferenceinterfaceClassThe annotation indicates that a service is referenced, and the interface can be specified with attributes

Special attention: in nacos, services between different namespaces (namespace) cannot call each other, and even if they are in the same namespace, but not in the same group, they cannot call each other. Quarantined
Related posts: https://developer.aliyun.com/ask/317473 Portal

Write a configuration file

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}

Start the main module and register it in Nacos

insert image description here

test

insert image description here

source address

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

Guess you like

Origin blog.csdn.net/daiyi666/article/details/121246849