在前面的两篇中,我们分别介绍了项目的基本架构、相关知识,和整合 MyBatis-Plus 、Knife4j。这一篇,我们来介绍在项目中整合 Nacos、OpenFeign。
1. 注册中心管理
1.1. 关于 Nacos
Nacos 是 Dynamic Naming and Configuration Service 的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos 的关键特性包括:服务发现和服务健康监测、动态配置服务、动态 DNS 服务、服务及其元数据管理。关于 Nacos 的更详细介绍请参考官方文档(链接地址)。
1.2. 版本选择
由于我们 Spring Cloud Alibaba 选择的是 2022.0.0.0 版本,其中的 nacos-client 版本为 2.2.1,我们的 nacos-server 也选择版本为 2.2.1。
1.3. 搭建 nacos-server
1.3.1. 下载 nacos-server
nacos-server-2.2. 1 可到 GitHub 进行下载( 链接地址)。
1.3.2. 安装 nacos-server
以 Linux 系统为例,我们将 Nacos 的 nacos-server-2.2.1.tar.gz 安装包下载下来,然后上传到Linux服务器,例如上传到”/soft“目录下。
第一步:输入 tar -zxvf nacos-server-2.2.1.tar.gz 命令进行解压,解压后如下所示。
第二步:创建数据库 mall-nacos,执行 nacos ”\conf“目录下的 mysql-schema.sql 文件。
第三步:修改 application.properties 配置文件信息,将数据源连接信息修改为 mysql ,如下所示。
注意:由于我们使用的 Nacos 是 2.2.1 版本,需执行以下变更。
nacos.core.auth.plugin.nacos.token.secret.key 的值为 Base 64 字符串,自己随便生成,长度超过32位即可。
第四步:进入到 nacos 的 bin 目录执行 ”./startup.sh -m standalone“ 命令进行启动。
执行”cat /soft/nacos/logs/start.out“命令,查看启动日志。
第五步:看到启动日志没报错,就可以打开浏览器输入”http://{ip}:8848/nacos/#/login“进行访问了。
输入用户名:nacos,密码:nacos,登录成功后如下所示。
1.4. 服务注册
1.4.1. 整合 Nacos
给每个模块的 start 工程添加如下依赖。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
然后,给 start 工程的启动类添加 @EnableDiscoveryClient 注解。例如,账户模块的启动类如下。
@Slf4j
@SpringBootApplication(scanBasePackages = {"org.example.account","org.example.component"})
@MapperScan("org.example.account.infra.mapper")
@EnableDiscoveryClient
public class MallAccountCenterApplication {
public static void main(String[] args) {
log.info("Begin to start Spring Boot Application");
long startTime = System.currentTimeMillis();
SpringApplication.run(MallAccountCenterApplication.class, args);
long endTime = System.currentTimeMillis();
log.info("End starting Spring Boot Application, Time used: "+ (endTime - startTime) );
}
}
最后,在 application.yml 文件中配置 nacos-server 的地址。
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
1.4.2. 注册中心测试
启动各个模块的服务,登录 nacos,可以看到 mall-account-service、mall-product-service、 mall-order-service 都在服务列表中了。
1.4.3. 名称空间与分组
1.4.3.1. 名称空间
名称空间(Namespace)用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
上面截图的服务列表中, mall-account-service、mall-product-service、 mall-order-service 三个服务,默认都注册到 public 名称空间下。为例区分开发环境和生成环境的配置信息,我们需要创建开发环境、生成环境的名称空间,让服务分别注册到对应的名称空间中。以开发环境为例,我们创建名称空间为:dev。如下图所示。
配置文件,给账户模块、商品模块、订单模块指定名称空间。以账户模块为例,配置如下。
重新启动账户模块、商品模块、订单模块,可以看到三个服务都注册到dev名称空间下了。
1.4.3.2. 配置分组
Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或 Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置和 MQ_topic 配置。
从上面的截图中可以看到,我们账户模块、商品模块、订单模块都是注册到 DEFAULT_GROUP 分组下的,我们给账户模块、商品模块、订单模块指定一个分组,取名为:mall。以账户模块为例,配置如下。
重新启动账户模块、商品模块、订单模块,可以看到三个服务都归到mall分组下了。
1.5. 服务发现
1.5.1. 功能需求
实现在订单模块根据商品id查询商品信息。
1.5.2. 需求实现
要实现"在订单模块根据商品 id 查询商品信息"的功能,涉及到跨服务调用,由商品服务提供接口,让订单服务来调用,我们可以通过集成 OpenFeign 来实现微服务之间的调用。
1.5.3. 关于 OpenFeign
OpenFeign 是 Spring Cloud 中的组件,是一个声明式 REST 客户端。关于 OpenFeign 更详细的介绍,可以参考官网(链接地址)。
1.5.4. 整合 OpenFeign
给商品模块中的 mall-product-center-client 工程添加必要的依赖,如下。
<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>
<parent>
<groupId>org.example.product</groupId>
<artifactId>mall-product-center</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>mall-product-center-client</artifactId>
<name>mall-product-center-client</name>
<description>api输出层</description>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--mall-product-center-dto-->
<dependency>
<groupId>org.example.product</groupId>
<artifactId>mall-product-center-dto</artifactId>
</dependency>
<!--spring-cloud-starter-openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--2020版本以后就已经移除了对ribbon的支持,而是使用LoadBalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>
在 mall-product-center-client 工程的 org.example.product.client 包目录下创建名称为 ProductClient 的接口,内容如下。
@FeignClient(name = BaseConstant.Domain.PRODUCT)
public interface ProductFeignClient {
@Operation(summary = "根据id查询商品信息")
@GetMapping(BaseConstant.AdapterType.CLIENT+"/product/v1/queryById/{id}")
@Parameter(name = "id",description = "商品id",required = true)
ProductRspDTO queryById(@PathVariable(value = "id") Long id);
}
其中,常量 BaseConstant.Domain.PRODUCT 对应服务名 mall-product-service。
在 mall-product-center-adapter 工程的 org.example.product.adapter.client 目录下添加 ProductClient 接口的实现类,名称为 ProductClientController ,内容如下。
@Slf4j
@Tag(name = "product-client端api")
@RestController
public class ProductClientController implements ProductFeignClient {
@Resource
private ProductExecutor productExecutor;
@Override
public ProductRspDTO queryById(Long id){
log.info("query product detail,id is :{}",id);
return this.productExecutor.queryProductById(id);
}
}
1.5.5. 本地接口测试
在 mall-product-center-dto 工程的 Knife4jConfig 类中新增 client 分组,代码如下。
@Bean
public GroupedOpenApi clientApi() {
return GroupedOpenApi.builder()
.group("adapter-"+BaseConstant.AdapterType.CLIENT)
.pathsToMatch("/"+ BaseConstant.AdapterType.CLIENT+"/**")
.build();
}
启动商品服务,访问 http://localhost:7040/doc.html ,打开 Knife4j 文档。选择 adapter-client 组。找到”根据id查询商品信息“ 接口,输入商品id,测试如下。
1.5.6. 跨服务调用测试
在订单模块的 mall-order-center-app 工程中添加 mall-product-center-client 工程的依赖,如下。
<!--mall-product-center-client-->
<dependency>
<groupId>org.example.product</groupId>
<artifactId>mall-product-center-client</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
在订单模块 mall-order-center-start 启动类添加 @EnableFeignClients 注解。
@Slf4j
@SpringBootApplication(scanBasePackages = {"org.example.order","org.example.component"})
@MapperScan("org.example.order.infra.mapper")
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "org.example.*")
public class MallOrderCenterApplication {
public static void main(String[] args) {
log.info("Begin to start Spring Boot Application");
long startTime = System.currentTimeMillis();
SpringApplication.run(MallOrderCenterApplication.class, args);
long endTime = System.currentTimeMillis();
log.info("End starting Spring Boot Application, Time used: "+ (endTime - startTime) );
}
}
在订单模块 mall-order-center-app 工程的 OrderExecutor 类中实现接口调用。
@Component
public class OrderExecutor {
@Resource
private OrderService orderService;
@Resource
private ProductFeignClient productFeignClient;
/**
*本地CRUD方法,省略粘贴。
*/
/**
* 根据商品id查询商品信息
*/
public ProductRspDTO queryProductById(Long id) {
return this.productFeignClient.queryById(id);
}
}
启动订单服务,访问 http://localhost:7050/doc.html ,打开 Knife4j 文档。选择 adapter-web 组。找到”根据id查询商品信息“ 接口,输入商品id,测试如下。
2. 配置中心管理
Nacos 不仅可以作为注册中心,还可以作为配置中,使用 Nacos 作为配置中心,可以更方便地对配置信息进行管理。
目前,我们的账户模块、商品模块、订单模块都涉及到数据库连接配置,可以使用 Nacos 将数据库连接配置信息抽取出来创建单独的文件,供各个模块使用。对应 Knife4j 的配置,也可以统一做成一个文件,供各个模块使用。
下面我们来实现使用 Nacos 作为配置中心。
2.1. 配置中心实现
给每个模块的 start 工程添加如下配置中心依赖。
<!-- nacos配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 2020.X.X版本官方重构了bootstrap引导配置的加载方式,需要添加以下依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
在 Nacos 中,分别创建 datasource.yaml、knife4j.yaml。
datasource.yaml 内容如下。
knife4j.yaml 内容如下。
配置列表如下所示。
将每个模块的 start 工程 resources 目录下的 application.yml 文件,改名为 bootstrap.yml 。这里修改文件名,是为了保证工程中的配置先于 Nacos 中的配置信息被加载。
配置信息加载顺序依次为:bootstrap.properties、bootstrap.yml、application.properties、application.yml 。
在每个模块的 start 工程 resources 目录下创建 bootstrap.properties 文件,该文件主要用来定义变量信息,供 bootstrap.yml 文件引用。以账户模块为例,bootstrap.properties 文件内容如下。
#nacos服务地址
NACOS_ADDR=127.0.0.1:8848
#nacos名称空间
NACOS_NAMESPACE=dev
#数据库名称
DB_NAME=mall-account
在 bootstrap.yml 文件中引用 Nacos 配置信息。以账户模块为例,bootstrap.yml 文件内容如下。
server:
port: 7030
spring:
application:
name: mall-account-service
cloud:
nacos:
discovery:
server-addr: ${NACOS_ADDR}
namespace: ${NACOS_NAMESPACE}
group: mall
config:
server-addr: ${NACOS_ADDR}
namespace: ${NACOS_NAMESPACE}
file-extension: yaml
group: mall
extension-configs:
- data-id: datasource.yaml
group: mall
refresh: true
- data-id: knife4j.yaml
group: mall
refresh: true
基于以上 bootstrap.yml 的配置,如果有新的组件(例如:redis)需要增加配置信息,我们就可以在 Nacos 上继续新增 yaml 文件,然后将 yaml 文件名追加到 bootstrap.yml 文件中即可。若是修改某个 yaml 文件的配置信息,则直接在 Nacos 上进行修改即可。
2.2. 配置中心测试
重新启动各个模块的服务,可以看到服务都正常注册。
测试"在订单模块根据商品 id 查询商品信息"的功能,也是正常返回。
3. 总结
本篇先介绍了 Nacos 的搭建。然后介绍了以 Nacos 作为注册中,实现微服务的注册与发现,并分别进行了测试。在介绍 Nacos 服务发现的过程中,我们集成了 OpenFeign 作为 REST 客户端,以实现跨服务之间的接口调用。最后介绍了用 Nacos 作为配置中心,以便更好地对配置信息进行管理。
基础篇项目代码:链接地址