Nacos registration and configuration center integrate Dubbo remote call (demo code address is included at the end of the article)
- background
- development environment
- Build the parent project
- build submodule
- Extract common code structures
- Write Dubbo-related code in the order module
- Start Nacos
- Enter the Nacos management interface to create a configuration file
- Register the order module with Naocs
- Write a service consumer module
- Start the main module and register it in Nacos
- test
- source address
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
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):
Declare dependencies
After creating the parent project, we then declare the various dependencies that we need to use in the middle dependencyManagement
tag 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 packaging
tags 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-plugin
the 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:
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:
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.Serializable
interface 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());
}
}
@DubboService
The 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.yaml
because 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
.
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;
}
@RefreshScope
The annotation indicates that the configuration information in this class will be refreshed dynamically
I created a configuration file order
named in the nacos configuration list, and the group configuration-files
is 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.yaml
it 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=true
configuration to the VM options configuration item of the order module:
After starting, we can see our service and exposed interface in the service list
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:
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();
}
}
@DubboReference
interfaceClass
The 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
test
source address
gitee:https://gitee.com/daiyi-personal/sunflower.git