微服务之Nacos(注册中心、配置中心)

微服务学习顺序:
微服务之Nacos
微服务之OpenFeign
微服务之网关

常见微服务架构

  1. dubbo: zookeeper +dubbo +SpringMVC/SpringBoot
    配套 通信方式:rpc
    注册中心:zookeeper(Apache) / redis
  2. SpringCloud:全家桶+轻松嵌入第三方组件(Netflix)
    配套 通信方式:http restful
    注册中心:eruka(Spring)
    配置中心:config
    断 路 器:hystrix
    网关:zuul
    分布式追踪系统:sleuth + zipkin
  3. SpringCloud Alibaba

我们最早学习的是单体式开发,再接着学习了分布式开发,而我们现在学习的微服务

一、什么是微服务?

微服务是一种将大型应用拆分成多个小型、独立服务的架构风格,而分布式是实现微服务的技术手段之一,Nacos 这类工具则是支撑微服务运行的基础设施。

微服务的核心是 "拆分" 与 "独立",把原本一个庞大的单体应用,按业务功能拆分成多个可独立开发、部署、运行的小型服务。

核心特征:

  • 单一职责:每个微服务只负责一个特定的业务领域,比如电商系统中的 "用户服务""订单服务""支付服务"。
  • 独立部署:某个服务升级或修复 bug 时,无需重启整个应用,只部署该服务即可,不影响其他服务。
  • 技术异构:不同服务可使用不同的编程语言、框架,比如 "订单服务" 用 Java,"推荐服务" 用 Python。
  • 独立数据存储:每个服务通常有自己的数据库,避免多个服务依赖同一数据库导致的耦合。

举个通俗例子:把一个大型电商 App 比作一家大型超市(单体应用),所有商品(功能)都在一个建筑里。而微服务就像把超市拆分成 "便利店""水果店""生鲜店"(不同服务),各自独立运营,互不干扰,但共同组成了零售体系。

二、微服务是怎么做的?(核心实现步骤与技术栈)

实现微服务需要一套完整的技术体系支撑,核心是 "拆分服务"+"解决服务间协作问题",分 4 个关键步骤。

  1. 第一步:服务拆分(核心前提)
    按业务边界拆分,而非技术层面。
  • 拆分原则:遵循 "高内聚、低耦合",一个服务内部功能紧密相关,服务之间依赖尽可能少。
  • 常见拆分方式:按业务域拆分,如电商系统可拆分为:
    • 用户服务:负责用户注册、登录、信息管理。
    • 商品服务:负责商品上架、库存管理、详情查询。
    • 订单服务:负责订单创建、状态更新、订单查询。
    • 支付服务:负责支付对接、退款处理。
  1. 第二步:服务通信(服务间协作)
    拆分后的服务之间需要通过接口相互调用(比如 "创建订单" 需要调用 "商品服务" 扣减库存),接口是服务间协作的唯一 "桥梁",不同服务通过约定好的接口规范实现数据交互和功能调用。
  • 服务之间接口调用的两种主流方式
    • REST API(最常用,轻量通用):基于 HTTP/HTTPS 协议,采用 JSON/XML 作为数据传输格式,接口地址通常是 URL 路径,简单通用,适合跨语言调用,比如 Java 服务调用 Python 服务。
    • RPC(远程过程调用,高性能):底层基于 TCP 协议(部分支持 HTTP2),数据传输采用二进制格式(如 Protobuf),性能比 REST API 更高,适合同语言服务间调用,如 Dubbo、gRPC。
  1. 第三步:核心支撑技术(解决微服务痛点)
    拆分后会出现新问题,这就涉及到服务治理,服务治理本质是一套保障微服务集群 "稳定、可控、高效" 运行的技术体系,用来解决服务拆分后出现的各种 "协作难题",比如服务调用失败、流量过载、故障扩散等。
问题场景 核心技术工具 作用说明
服务太多,怎么找到对方 服务注册与发现(Nacos/Eureka) 服务启动后自动 "上报" 地址到注册中心,调用方从注册中心 "查询" 地址,无需硬编码。
服务调用失败怎么办 服务熔断降级(Sentinel/Hystrix) 某个服务故障时,快速返回降级结果,避免连锁崩溃(比如支付服务挂了,订单服务暂存订单)。
多个服务调用,怎么追踪 分布式链路追踪(SkyWalking/Zipkin) 记录一次请求经过的所有服务,快速定位哪个服务出问题(比如用户下单失败,追踪到是库存服务超时)。
配置太多,怎么统一管理 配置中心(Nacos/Apollo) 所有服务的配置(如数据库地址、参数)集中存储,修改后实时推送,无需逐个服务重启。
  1. 第四步:部署与监控(保障服务运行)
  • 部署:通过容器化(Docker)打包服务,结合编排工具(K8s)实现自动化部署、扩容缩容。
  • 监控:通过 Prometheus+Grafana 监控服务的 CPU、内存、接口调用量等指标,及时发现异常。

微服务与分布式的区别:

  • 微服务是按 "业务功能" 拆分,拆分的结果是 "独立服务"。
  • 分布式是按 "技术模块" 或 "负载" 拆分,拆分的结果是 "同一应用的不同节点 / 模块。

三、nacos简介

nacos是spring cloud alibaba生态中非常重要的一个组件,它有两个作用:注册与发现中心、配置中心。

nacos有注册中心的作用,我们常见的配置中心还有zookeeper和eureka。

官网:https://nacos.io/zh-cn/index.html

微服务cap原则:

  1. C(consistency):一致性,同一时刻的同一请求的实例返回结果相同,属于强一致性性,也就是说,在集群环境中,对外提供的服务信息是完全一致的,但是在效率上面可能会有一定的损耗;
  2. A(availability):可用性,所有实例的读写请求在一定的时间内可以得到正确的响应,它是弱一致性,可能在极短的时间内,不同实例获取到的信息是不一致的,但是服务可用并且最终数据是一致的;
  3. P(Partition tolerance):分区容错性,在网络异常的情况下,仍旧能够提供正常的响应,这是在微服务系统中必须要保证的;
配置中心 CAP理论 控制台(可视化界面)
nacos CP/AP
zookeeper CP
eureka AP

nacos在启动时,默认是AP模式,可以通过指令将nacos变为CP模式,在我们经常使用的微服务中,我们是选择使用AP模式的,此时的所有实例都属于临时实例。临时实例和持久实例最显著的区别就是在健康检查发现服务有问题时,持久实例被标注为不健康,而临时实例会直接剔除。

四、nacos基本使用

nacos大体分为两部分:nacos服务端 和 nacos客户端。

4.1 nacos服务端

首先是nacos服务端 ,这一部分是不需要做任何改动,直接启动服务即可。有两种方式。

  • 一种是直接下载打包好的服务,直接通过命令运行即可。
  • 一种是下载nacos源码,然后进行启动(nacos是普通的spring boot项目)。

1. 直接下载打包服务

第一步,去nacos官网下载对应环境的服务端项目,下载地址是:https://github.com/alibaba/nacos/releases。但是需要注意一点,目前在nacos官网(Nacos 快速开始)中,推荐使用的nacos版本是2.2.3

下载完毕以后进行解压(不要有中文路径),进入到bin目录

在该目录下打开cmd命令窗口(也可以按住shift,右击空白处,选择打开Powershell窗口),输入下面的命令启动:

cmd 复制代码
.\startup.cmd -m standalone

使用命令启动,后缀standalone指的是以单例的方式进行启动。
注意:直接双击startup.cmd启动是以集群的形式启动,我们这里要的是单例形式启动。

默认端口号是8848。

浏览器访问Nacos可视化界面:http://192.168.150.1:8848/nacos/index.html,其中192.168.150.1是本机IP。

注意:默认登录账号和密码均为:nacos

2. 源码方式启动

下载源码https://github.com/alibaba/nacos导入idea中。

启动类在console子项目中,编译启动即可。

4.2 创建nacos客户端

1. 创建父级项目

在IDEA中创建SpringBoot项目,命名为cloud-alibaba-test,充当父级项目

勾选Nacos Service Discovery

我们可以把src目录删去,不需要。

2. 创建子项目

右击父项目->new->module

创建SpringBoot项目,命名为bill-7780

勾选Spring Web

删除默认生成的demos.web目录

3. 修改子项目pom文件

需要把下面的父级项目的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.lp</groupId>
    <artifactId>bill-7780</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bill-7780</name>
    <description>bill-7780</description>

    <!--指定父级-->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>cloud-alibaba-test</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <!--指定打包方式-->
    <packaging>jar</packaging>

    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.7.6</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    
    <dependencyManagement>

    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!--启动类插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.lp.Bill7780Application</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

4. 修改父级项目的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>cloud-alibaba-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloud-alibaba-test</name>
    <description>cloud-alibaba-test</description>

    <!--指定子模块-->
    <modules>
        <module>bill-7780</module>
    </modules>
    <!--指定父级项目打包方式-->
    <packaging>pom</packaging>

    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.7.6</spring-boot.version>
        <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.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.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.cloudalibabatest.CloudAlibabaTestApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

5. 使用@EnableDiscoveryClient注解开启Nacos

可以在子项目中使用@EnableDiscoveryClient注解创建开启Nacos的配置类,如下。也可以直接在启动类上使用该注解。

java 复制代码
package com.lp.config;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Configuration;

@EnableDiscoveryClient// 开启nacos服务注册与发现
@Configuration
public class NacosDiscoveryClientConfig {
}

6. application.yml进行配置(注册服务到nacos)

yml 复制代码
server:
  port: 7780
spring:
  application:
    name: bill-7780 #往注册中心放的服务名称,一般与项目名保持一致(服务名称不能重复)
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos

运行启动类,启动项目。

可以看到Nacos可视化界面的服务列表中有了一个服务。

同样的我们可以再创建一个子项目provider-7790,并添加到Nacos服务中心。

五、nacos集群配置

Nacos集群默认最小要有三个节点(跟Redis集群类似,保证如果其中一个挂了,还有另外的nacos支撑着),而且三个节点的配置中心的数据都需要存储在MySQL数据库中。

nacos持久化

如果要做集群,就涉及到服务的同步问题:

假如有三个nacos服务端,我们注册一个服务到其中一个nacos中(我们记为nacos01),但并没有在另外两个nacos注册这个服务。我们想要的是如果nacos01挂掉了,我们还有另外两个nacos管理着这个服务。那么如何让这三个nacos同步管理服务呢?很简单,就是依靠数据库来实现。

一旦有服务进到nacos01中,就把服务信息记录到数据库中,把这三个nacos都连接到这个数据库,自然就实现了同步。

在mysql中创建数据库nacos_config,并在nacos的conf目录下找到mysql-schema.sql文件导入该数据库。

修改nacos的conf目录下的application.properties文件

打开数据库连接并修改连接信息,以及设置端口号

在conf目录下,修改文件名cluster.conf.example为cluster.conf

并编辑cluster.conf文件信息如下: IP(可cmd命令窗口使用ipconfig命令查看自己的IP地址)+端口号

txt 复制代码
192.168.108.21:8850
192.168.108.21:8860
192.168.108.21:8870

注意:端口号不要连续,如8081,8082,8083。连续端口会报错。

再复制nacos文件夹两份(nacos最小3个节点)

修改nacos2端口为8860,修改nacos3端口为8870

依次启动nacos1,nacos2,nacos3

进入bin目录下,双击启动startup.cmd (默认以集群模式启动)

注意 :切记不要使用.\startup.cmd -m standalone 启动,需要以cluster模式启动。

浏览器访问nacos控制台(IP+端口号):

http://192.168.108.21:8850/nacos/index.html

http://192.168.108.21:8860/nacos/index.html

http://192.168.108.21:8870/nacos/index.html

登录密码和账号都是:nacos

点击集群管理的节点列表,查看是否配置成功

启动前面创建的子项目bill-7780(这里需要修改一下 .yml文件中的配置的nacos端口为8850),注册服务。

浏览器访问http://192.168.108.21:8850/nacos/index.html

再分别访问http://192.168.108.21:8860/nacos/index.html、http://192.168.108.21:8870/nacos/index.html的服务列表,会发现3个nacos同步服务。

5.1 集群启动后多一个节点问题

Nacos在集群启动时,如果没有明确指定要使用的 IP 地址,它会自动扫描主机上的所有可用的网卡IP(可在cmd窗口使用 ipconfig 命令查看),并优先选择 "第一个有效 IP"(按系统网卡枚举顺序,第一个不一定是本机IP) 作为节点 IP 注册到集群中。

可临时禁用虚拟网卡使其不可用,进行测试:控制面板→网络和 Internet→网络连接,右击网卡选择禁用。

Nacos实例实际绑定的 IP 与cluster.conf中配置的不一致,导致该实例被识别为 "新节点" 并自动加入集群,从而导致集群中出现额外节点(可在nacos可视化界面的节点列表查看)。

5.1.1 解决方法:设置nacos强制绑定使用本机IP

  • 方式一:记事本打开startup.cmd,找到 Java 启动命令行(所有的 Nacos 实例(端口)都需要修改对应的startup.cmd),在末尾添加参数:
bash 复制代码
-Dnacos.inetutils.ip-address=本机IP
  • 方式二:通过 "配置文件" 指定 IP(适合固定网络环境)
    如果希望通过配置文件统一管理,可在application.properties中添加 IP 配置,无需每次修改启动脚本:
properties 复制代码
# 强制指定Nacos启动时使用的IP
nacos.inetutils.ip-address=本机IP

六、nacos配置中心(持久化存储配置信息)

在微服务中,我们要拆分服务,每个微服务项目都要配置 .yml文件 且都要配置数据库连接等。修改起来比较麻烦,且数据库用户名和密码在 .yml文件中是明文的,不安全。我们可以将这些配置提取到nacos中进行统一管理。

nacos同spring-cloud-config一样,可以作为一个配置中心,统一的来管理配置,可以配置多套环境,各个微服务可以按需到nacos配置中心拉取相关配置,且支持动态刷新@RefreshScope。

在Nacos配置中心的配置的参数信息是持久化存储的,不会因为 Nacos 服务重启或宕机丢失。

6.1 项目准备

在前面的父级项目cloud-alibaba-test下创建项目模块cloud-common,此项目仅充当提供公共配置和公共类等的角色,不需要启动,创建maven项目即可。

可删除webapp文件夹,我们这里不需要。

修改子项目cloud-common的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">
    <parent>
        <artifactId>cloud-alibaba-test</artifactId>
        <groupId>com.example</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    
	<!--groupId、version如果没有生成,可以自行添加-->
    <groupId>com.lp</groupId>
    <artifactId>cloud-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <artifactId>cloud-common</artifactId>
    <packaging>jar</packaging>

    <name>cloud-common Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        
    </dependencies>

    <build>
        <finalName>cloud-common</finalName>
    </build>
</project>

修改父级项目cloud-alibaba-test的pom文件,添加lombok依赖

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

在子项目cloud-common中创建实体类bill

java 复制代码
package com.lp.pojo;

import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

@Data
public class Bill{
	private Long id;   //id
	private String billCode; //账单编码
	private String productName; //商品名称
	private String productDesc; //商品描述
	private String productUnit; //商品单位
	private Integer productCount; //商品数量
	private BigDecimal totalPrice; //总金额
	private Integer isPayment; //是否支付
	private Integer providerId; //供应商ID
	private Integer createdBy; //创建者
	private Date creationDate; //创建时间
	private Integer modifyBy; //更新者
	private Date modifyDate; //更新时间
}

在子项目cloud-common中添加公共返回工具类ResultAjax

java 复制代码
package com.lp.utils;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
public class ResultAJAX implements Serializable {

    private Integer code;
    private String msg;
    private Object data;

    public ResultAJAX(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static ResultAJAX success(){
        return  new ResultAJAX(0,"操作成功",null);
    }
    public static ResultAJAX success(Object data){
        return  new ResultAJAX(0,"操作成功",data);
    }

    public static ResultAJAX error(){
        return  new ResultAJAX(-1,"操作失败",null);
    }


    public static ResultAJAX error(String msg){
        return  new ResultAJAX(-1,msg,null);
    }
}

可能有些子项目不需要引入mybatis-plus,在父级项目的pom文件中引入是不合适的,所以我们要单独引入到指定子项目中,比如我们在子项目bill-7780的pom文件中需要引入mybatis-plus和mysql数据库驱动依赖

xml 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

此时我们的子项目cloud-common中的bill实体类是无法使用mybatis-plus的实体类与数据库的映射功能的。但如果又想用,又该怎么办:

  • 确保父级项目的pom文件中将cloud-common配置为其子项目
xml 复制代码
<modules>
    <module>bill-7780</module>
    <module>provider-7790</module>
    <module>cloud-common</module>
</modules>
  • 在子项目bill-7780的pom文件中引入cloud-common子项目
xml 复制代码
<dependency>
    <groupId>com.lp</groupId>
    <artifactId>cloud-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
  • 我们在子项目bill-7780中创建实体类SmbmsBill继承Bill,这样我们就可以在子项目bill-7780中使用mybatis-plus的映射功能了
java 复制代码
package com.lp.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.lp.pojo.Bill;

@TableName("smbms_bill")
public class SmbmsBill extends Bill {
}

在子项目bill-7780中创建如下:

  • 创建mapper接口
java 复制代码
package com.lp.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lp.entity.SmbmsBill;

public interface SmbmsBillMapper extends BaseMapper<SmbmsBill> {
}
  • 创建service接口
java 复制代码
package com.lp.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.lp.entity.SmbmsBill;
import com.lp.utils.ResultAJAX;

public interface SmbmsBillService extends IService<SmbmsBill> {
    public ResultAJAX findList();
}
  • 实现service接口
java 复制代码
package com.lp.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lp.entity.SmbmsBill;
import com.lp.mapper.SmbmsBillMapper;
import com.lp.service.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.stereotype.Service;

@Service
public class SmbmsBillServiceImpl extends ServiceImpl<SmbmsBillMapper, SmbmsBill> implements SmbmsBillService {
    @Override
    public ResultAJAX findList() {
        return ResultAJAX.success(this.list());
    }
}

创建BillController

java 复制代码
package com.lp.controller;

import com.lp.service.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/bill")
public class BillController {

    @Autowired
    private SmbmsBillService smbmsBillService;

    @GetMapping("/list")
    public ResultAJAX findList(){
        return smbmsBillService.findList();
    }

}

在子项目bii-7780的启动类添加@MapperScan注解扫描mapper(dao)层

java 复制代码
package com.lp;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.lp.mapper")
public class Bill7780Application {

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

}

在子项目bill-7780的.yml文件配置数据库、mybatis-plus

yml 复制代码
server:
  port: 7780
spring:
  # 数据源
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&tinyInt1isBit=false&allowLoadLocalInfile=true&allowLocalInfileInMultiQueries=true&allowUrlInLocalInfile=true&allowPublicKeyRetrieval=true&allowMultiQueries=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
  application:
    name: bill-7780 #往注册中心放的服务名称,一般与项目名保持一致(服务名称不能重复)
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8850
        username: nacos
        password: nacos
# mybatis-plus配置
mybatis-plus:
  type-aliases-package: com.lp.entity # 使用别名
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印sql
    map-underscore-to-camel-case: false # 关闭驼峰映射

运行子项目bill-7780(因为配置了nacos,所以需要先启动nacos)

浏览器访问http://localhost:7780/bill/list

6.1.1 在nacos配置中心配置

假如项目已经上线了,如果此时想修改子项目bill-7780的 .yml 配置信息,那该怎么办?正常来说我们需要打开我们的服务去修改,很麻烦。对于像数据库用户名和密码之类的重要的配置信息,在 .yml 中是明文的,不安全。我们可以把这些重要的yml配置信息,配置到nacos中,让 .yml 去nacos中拉取这些信息。这样,我们就可以直接在nacos中更方便的修改项目的配置信息。

  1. 进入nacos控制台创建命名空间(相当于创建了一个文件夹)

    注意:命名空间以后在开发中可以区分为 开发、测试、生产 等环境。

  2. 在smbms命名空间下创建yaml文件

Data ID不能随便起,需要满足下面与bootstrap.yml中服务配置的匹配规则,一般命名为:服务名-dev.yaml(其中服务名是指项目在nacos中注册的服务名)。

6.1.2 拉取配置

我们将数据库用户名和密码等信息配置在canos中,就需要让项目在加载application.yml之前,去canos拉取到数据库用户名和密码等配置信息。

这就需要再创建一个bootstrap.yml(系统指定文件名,不能随便改)文件,它会在application.yml执行之前先去执行 ,从canos拉取配置信息。(可借助bootstrap.yml提前加载一些配置)

  1. 在子项目bill-7780的pom文件中引入配置中心和bootstrap依赖
xml 复制代码
<!--nacos配置中心-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <!--这里版本不需要指定,父级项目已经指定了,跟随父级项目的版本-->
</dependency>

<!--开启Spring Cloud应用程序启动时加载bootstrap配置文件-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
    <version>3.1.4</version>
</dependency>
  1. 创建bootstrap.yml
yml 复制代码
server:
  port: 7780
spring:
  profiles:
    active: dev
  application:
    name: bill-7780 #往注册中心放的服务名称,一般与项目名保持一致(服务名称不能重复)
  # 注册服务
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8850 # nacos注册中心地址
        username: nacos
        password: nacos
      config:
        server-addr: 127.0.0.1:8850 # nacos配置中心地址
        file-extension: yaml
        group: DEFAULT_GROUP # 配置分组
        namespace: 935f0c39-db1c-4fc0-a997-35cd6f929740 # 命名空间ID

Nacos 是先读取 bootstrap.yml 中的配置,再根据 bootstrap.yml 中的以下配置自动拼接 Data ID:Data ID = ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension},最后与 Nacos 中实际存在的 Data ID 进行比对匹配。

修改application.yml文件

yml 复制代码
spring:
  # 数据源
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&tinyInt1isBit=false&allowLoadLocalInfile=true&allowLocalInfileInMultiQueries=true&allowUrlInLocalInfile=true&allowPublicKeyRetrieval=true&allowMultiQueries=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: ${mysql.uname}
    password: ${mysql.upwd}
# mybatis-plus配置
mybatis-plus:
  type-aliases-package: com.lp.entity # 使用别名
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印sql
    map-underscore-to-camel-case: false # 关闭驼峰映射

注意: 使用nacos作为配置中心时,需要创建一个bootstrap.yml和application.yml两个配置文件,bootstrap.yml的优先级高于application.yml,加载时实现优先加载bootstrap.yml中的相关配置。

  1. 启动bill-7780项目
    浏览器访问http://localhost:7780/bill/list,能正常访问

6.2 @RefreshScope

我们的一些配置是放在nacos中的。项目启动时,会去nacos中拉取这些配置。当项目已经启动,这时如果我们在nacos中的配置中心去修改这些配置信息,是无法立即应用到这个已经启动的项目中的。我们需要重新启动项目才会再次去nacos配置中心拉取配置。

这时就有一个问题,如果项目一直启动着,我们在nacos配置中心的修改就不会起作用。

而使用@RefreshScope就可以实现在项目还在运行时,修改nacos配置中心的配置,会立即动态应用到这个运行中的项目。

在 Nacos 中,@RefreshScope 是 Spring Cloud 提供的注解,用于实现配置的动态刷新。它的核心作用是:当 Nacos 配置中心的配置内容发生变更时,被该注解标记的 Bean 会被重新创建,从而加载最新的配置,避免应用重启。

比如如果没有 @RefreshScope,当 Nacos 中 mysql.uname 变更后,userName 的值不会更新,必须重启应用才会生效;加上注解后,配置变更会触发 ConfigService 重新实例化,获取最新值。

测试

修改子项目bill-7780的控制器

java 复制代码
package com.lp.controller;

import com.lp.service.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/bill")
public class BillController {
    @Value("${mysql.uname}")//使用Spring的@Value注解(不是lombok的@Value注解) 获取从nacos中拉取过来的配置信息
    private String uname;

    @Autowired
    private SmbmsBillService smbmsBillService;

    @GetMapping("/list")
    public ResultAJAX findList(){
        System.out.println("uname====="+uname);//打印拉取的配置信息
        return smbmsBillService.findList();
    }

}

启动子项目bill-7780,浏览器访问http://localhost:7780/bill/list,查看控制台。

修改nacos中的配置

再次访问http://localhost:7780/bill/list,会发现控制台中打印的仍是uname=====root,没有变。但我们希望的是它能够改变,这时可以在控制器上面加一个`@RefreshScope`注解

java 复制代码
package com.lp.controller;

import com.lp.service.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/bill")
@RefreshScope
public class BillController {
    @Value("${mysql.uname}")//使用Spring的@Value注解(不是lombok的@Value注解) 获取从nacos中拉取过来的配置信息
    private String uname;

    @Autowired
    private SmbmsBillService smbmsBillService;

    @GetMapping("/list")
    public ResultAJAX findList(){
        System.out.println("uname====="+uname);//打印拉取的配置信息
        return smbmsBillService.findList();
    }

}

重启子项目bii-7780,浏览器访问http://localhost:7780/bill/list,会访问不到(因为数据库连接用户名信息是错误的),但可以在控制台看到打印uname=====123

修改nacos配置中心的数据库连接用户名信息为正确的用户名

不重启bill-7780,浏览器直接访问http://localhost:7780/bill/list,依旧会访问失败(下面解释),但可以在控制台看到打印uname=====root

要通过 @RefreshScope 实现数据库连接信息的动态修改(无需重启应用),必须 在手动创建的数据源配置类 上使用 @RefreshScope,不能通过SpringBoot的自动配置实现。

Spring Boot 自动配置的数据源默认是单例 Bean,不会随配置变更刷新。因此,需要禁用自动配置的数据源,并手动创建支持动态刷新的数据源 Bean(添加 @RefreshScope)。

这里就不演示动态修改数据库连接配置信息了。

未完待续。。。微服务之OpenFeign

相关推荐
长空任鸟飞_阿康11 分钟前
多模态 Agent 技术全景解析 — 从模型能力、Agent 架构到工程化与商业落地
人工智能·架构
代码笔耕13 分钟前
面向对象开发实践之消息中心设计(二)
java·后端·架构
狗哥哥23 分钟前
Vite 插件实战 v2:让 keep-alive 的“组件名”自动长出来
前端·vue.js·架构
法欧特斯卡雷特27 分钟前
Kotlin 2.3.0 现已发布!又有什么好东西?
后端·架构·开源
a努力。44 分钟前
小红书Java面试被问:ThreadLocal 内存泄漏问题及解决方案
java·jvm·后端·算法·面试·架构
测试人社区-小明44 分钟前
涂鸦板测试指南:从基础功能到用户体验的完整框架
人工智能·opencv·线性代数·微服务·矩阵·架构·ux
前端不太难1 小时前
RN 遇到复杂手势(缩放、拖拽、旋转)时怎么设计架构
javascript·vue.js·架构
人机与认知实验室1 小时前
新型人机环境系统智能结构:动态隔离与协同优化的三元架构
架构
2501_924064111 小时前
2025年优测平台:微服务全链路性能瓶颈分析与最佳实践
微服务·云原生·架构·性能瓶颈·全链路性能
IALab-检测行业AI报告生成1 小时前
AI驱动万页报告审核革新:IACheck技术架构与实践价值解析
人工智能·架构