Featured image of post Nacos

Nacos

Java微服务学习笔记之Nacos使用

Nacos—注册中心&配置中心

Nacos官网| Nacos 配置中心 | Nacos 下载| Nacos 官方社区

什么是注册中心Nacos

Nacos两大核心功能:服务注册与服务发现

安装Nacos

https://nacos.io/download/release-history/?spm=5238cd80.2ef5001f.0.0.3f613b7c4NDiBh

直接下载zip压缩包,解压后运行即可

1
startup.cmd -m standalone

访问:http://127.0.0.1:8848/nacos

Nacos服务注册功能

启动微服务

在service-order微服务模块中写一个SpringBoot的启动类

创建配置文件application.properties

1
2
3
spring.application.name=service-order            //服务名称
sercer.port=8000                                //服务启动端口
spring.cloud.nacos.server-addr=127.0.0.1:8848   //nacos地址

此时访问本地nacos服务器,发现nacos中存在service-order即注册成功

集群模式启动测试

控制台右键复制配置

编辑配置,将端口改一下运行即可,如下图所示

此时nacos注册中心实例数就有3个了

Nacos服务发现

开启服务发现功能

在SpringBoot的启动类中添加注解@EnableDiscoveryClient

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


@EnableDiscoveryClient    //开启服务注册与发现功能
@SpringBootApplication
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
}

测试服务发现API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@SpringBootTest
public class productTest {

    @Autowired
    DiscoveryClient discoveryClient;

    @Test
    public void discoveryClient() {
        // 服务注册与发现功能的测试代码
        discoveryClient.getServices().forEach(service ->
                System.out.println("service"+service)
        );
        //获取服务的IP和端口信息
        discoveryClient.getInstances("product-service").forEach(instance ->
                System.out.println("instance"+instance.getHost()+"\n"+instance.getPort()+"\n"+instance.getUri())
        );
    }
}

使用nacosServiceDiscovery进行服务发现测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    @Autowired
    NacosServiceDiscovery nacosServiceDiscovery;  //获取服务信息


    @Test
    void nacosServiceDiscovery() throws NacosException {
        // 服务注册与发现功能的测试代码
        nacosServiceDiscovery.getServices().forEach(service ->
                System.out.println("service"+service)
        );
        //获取服务的IP和端口信息
        nacosServiceDiscovery.getInstances("product-service").forEach(instance ->
                System.out.println("instance"+instance.getHost()+"\n"+instance.getPort())
        );
    }

4.远程调用—下单场景

远程调用基本流程

首先要定义两个微服务模块,分别是order模块和product模块,分别在这两个模块中编写对应的逻辑代码,这两个模块不需要写实体类pojo,将所有微服务的实体类抽取出来放到model模块统一管理

order和product模块要使用实体类直接在pom文件中加载依赖即可,如果不这样做的话如果订单模块要使用product模块就会很麻烦

负载均衡API测试

根据配置的策略从可用实例中选择一个,默认使用轮询算法,这次调用9001,下次调用9002,在又是9001

1
2
3
4
5
//在order的pom文件中引入对应依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@SpringBootTest
public class LoadBalancerTest {

    LoadBalancerClient loadBalancerClient;

    @Test
    public void test(){
        ServiceInstance choose = loadBalancerClient.choose("product-service");
        System.out.println(choose.getHost()+":"+choose.getPort());
        ServiceInstance choose1 = loadBalancerClient.choose("product-service");
        System.out.println(choose1.getHost()+":"+choose1.getPort());
        ServiceInstance choose2 = loadBalancerClient.choose("product-service");
        System.out.println(choose2.getHost()+":"+choose2.getPort());
    }

}

使用@LoadBanlancer注解完成负载均衡调用

1
2
3
4
5
6
//将注解放到远程调用客户端上即可
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    private product getProductFromRemote2(Long productId) {
        // 1. 获取商品服务所在的 IP 地址

        // 2. 构造请求 URL,product-service微服务的IP地址
        String url = "http://product-service/product/" + productId;
        // 3. 发送请求,获取商品信息
        log.info("请求URL: {}", url);
        product product = restTemplate.getForObject(url, product.class);
        return product;
    }

**面试题:**注册中心Nacos如果宕机,那么还能成功完成远程调用吗?

1.注册中心如果宕机,以前调用过那么可以从示例缓存中获取IP地址,还能成功完成远程调用

2.注册中心宕机,如果以前没调用过,那么第一次需要在注册中心获取地址,不能完成远程调用

Nacos配置中心

动态刷新

1
@Value("${xxx}")获取配置+@RefreshScope实现自动刷新

项目中使用方法:

1.启动Nacos

2.导入Nacos作为配置中心的依赖

1
2
3
4
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

3.在配置文件properties编写配置

1
2
3
4
spring.application.name=service-order
sercer.port=8000
spring.cloud.nacos.server-addr=127.0.0.1:8848
spring.config.import=nacos:service-order.properties  //指定导入的配置文件

4.在创建data-id数据集

要使用这些配置文件,可以使用Value注解加载

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    @Value("${order.timeout}")
    String orderTimeouut;
    @Value("${order.auto-confirm}")
    String orderConfirm;

    @GetMapping("/config")
    String config(){
        System.out.println("orderTimeouut:"+orderTimeouut);
        System.out.println("orderConfirm:"+orderConfirm);
        return orderTimeouut+" "+orderConfirm;
    }

此时如果直接修改Nacos配置文件的值,这个配置文件是不会自动刷新的,如果想要开启自动刷新的话,需要使用注解在类上添加

1
@RefreshScope          //开启配置文件自动刷新注解

一旦项目导入了Nacos的配置中心,那么项目启动前配置文件必须导入Nacos的配置,如果没有导入那么项目会启动报错

1
2
3
4
两种解决方法
1.禁用Nacos的导入检查
spring.cloud.nacos.config.import-check.enabled=false
2.设置Nacos的导入为可选的不是必须的

无感知自动刷新

创建一个properties配置类


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.example.properties;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "order")
public class OrderProperties {
    
    String timeouut;

    String autoconfirm;
}

想要使用配置文件直接依赖注入即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 @Autowired
    OrderProperties orderProperties;


    @GetMapping("/config")
    String config(){
        System.out.println("orderTimeouut:"+orderProperties.getTimeout());
        System.out.println("orderConfirm:"+orderProperties.getAutoconfirm());
        return orderProperties.getTimeout()+" "+orderProperties.getAutoconfirm();
    }

配置监听

先说一个场景:当Nacos的配置文件发生变更时发送邮件给开发者

  • 项目启动时监听Nacos配置文件变化 1. 获取最新的配置数据 2. 发送邮件通知开发者
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.example;

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.client.config.NacosConfigService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;

import java.util.concurrent.Executor;

@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {

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

    /**
     * 项目启动时监听Nacos配置文件变化
     * 1. 获取最新的配置数据
     * 2. 发送邮件通知开发者
     */
    @Bean
    public ApplicationRunner runner(NacosConfigManager nacosConfigManager) {
        return args -> {
            NacosConfigService nacosConfigService = (NacosConfigService) nacosConfigManager.getConfigService();
            
            nacosConfigService.addListener(
                "com.example.OrderProperties",
                "defaultGroup",
                new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return Runnable::run; // 修正:原代码中的Executor.newFixedThreadPool(4)不正确
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        System.out.println("配置文件更新了,最新的配置信息为:" + configInfo);
                        
                        // 发送邮件通知开发者
                        // 此处省略发送邮件的代码
                        System.out.println("邮件已发送");
                    }
                }
            );
        };
    }
}

思考:如果Nacos的配置文件数据集和项目中的配置文件有相同项,哪个会生效?

先导入优先,外部优先,所以Nacos的配置文件会优先生效

1
2
3
4
5
6
spring.application.name=service-order
sercer.port=8000
spring.cloud.nacos.server-addr=127.0.0.1:8848
spring.config.import=nacos:service-order.properties,nacos:common.properties
//service-order.properties优先级最高common.properties第二高
spring.cloud.nacos.config.import-check.enabled=false

数据隔离

先说场景:假设现在有这么一个需求:项目有多套环境:开发,测试,生产环境,而每一个环境在每套环境下配置文件都不一样

难点:区分多套环境,区分多种配置,区分多种微服务该怎么解决

解决方法:

使用Namespace名称空间区分多套环境,使用Group分组区分多种微服务,使用Data-id数据集区分多种配置

如何实现呢???
1.在Nacos的命名空间中新建名称空间

2.创建好开发测试生产环境的命名空间后,在配置管理者找到对应空间,新增配置

3.动态切换环境

在微服务的配置文件中定义命名空间和组名,但是这样子不能实现动态切换环境

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
sercer:
  port: 8000

spring:
  application:
    name: service-order
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      import-check:
        enabled=false:
      config:
        namespace: dev
  config:
    import:
      - nacos:Common.properties?group=order
      - nacos:database.properties?group=order

完整的配置文件如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
sercer:
  port: 8000

spring:
  profiles:
    active: dev         //选择dev环境的配置文件
    //active:test      //选择test环境下的配置文件
  application:
    name: service-order
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      import-check:
        enabled=false:
      config:
        namespace: ${spring.profiles.active:public}

---         //三个杠表示多文档模式
spring:
  config:
    import:
      - nacos:Common.properties?group=order
      - nacos:database.properties?group=order
    activate:
      on-profile: dev
---
spring:
  config:
    import:
      - nacos:Common.properties?group=order
      - nacos:database.properties?group=order
      - nacos:redis.properties?group=order
    activate:
      on-profile: test
---
spring:
  config:
    import:
      - nacos:Common.properties?group=order
      - nacos:database.properties?group=order
      - nacos:haha.properties?group=order
    activate:
      on-profile: prod

By Lsec
最后更新于 Jun 08, 2025 15:21 +0800
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计
¹鵵ҳ