Skip to content

Spring Cloud Nacos

Nacos 是一个由阿里巴巴开源的平台,支持服务注册与发现、动态配置管理、负载均衡等功能,广泛应用于微服务架构。

1. 运行Nacos[单机版]

本小节介绍如何在Docker上启动Nacos,命令如下:

bash
docker run --name nacos-standalone \
    -e MODE=standalone \
    -p 8848:8848 \
    -p 9848:9848 \
    -p 9849:9849 \
    -d nacos/nacos-server:v2.4.3

启动成功后,打开任意浏览器,输入地址:http://127.0.0.1:8848/nacos, 即可进入Nacos控制台页面。

image-20250707150905529

2. 服务注册与发现中心

Nacos可以作为服务注册与发现中心。

  • 微服务启动时,告诉Nacos本服务的地址与服务名,Nacos保存服务名到地址的映射关系,也就是服务注册;
  • 微服务可以通过服务名从Nacos查询到其他服务的地址,从而实现远程调用,也就是服务发现;

2.1 引入依赖

由于微服务都要引入Nacos服务注册与发现功能,所以在微服务的共同父项目pom.xml中引入如下依赖:

xml
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>${version}</version> 
</dependency>

这样,不管是服务提供者还是服务消费者,都有相关依赖了。

2.2 开启服务注册功能

application.properties文件中配置服务名、地址与Nacos的地址:

properties
server.port=9001
spring.application.name=product-service

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

在任一配置类上通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能:

java
@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
}

在product微服务中,有接口如下:

java
@RestController
public class ProductController {

    @GetMapping("/product/{id}")
    public Product getProduct(@PathVariable("id") Long id){
        Product product = new Product();
        product.setId(id);
        product.setName("手机" + id);
        product.setPrice(new BigDecimal("1000.00"));
        product.setStock(100);
        return product;
    }

}

2.3 服务发现功能

当服务注册到Nacos上后,我们可以使用RestTemplate + @LoadBalanced远程调用微服务。

由于服务提供者可能不止一个,所以使用负载均衡算法调用,首先引入依赖:

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

然后在order微服务容器中注入RestTemplate

java
@Configuration
public class Config {

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

最后,在OrderController中调用其他微服务:

java
@RestController
public class OrderController {

    @Resource
    private RestTemplate restTemplate;
    

    @GetMapping("/getProductFromOrder/{productId}")
    public Product getgetProductFromOrderOrder(@PathVariable("productId") Long id){
      	// product-service 为服务名
        String url = String.format("http://product-service/product/%s",id);
        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }


}

DANGER

注意,在使用restTemplate调用其他微服务时,不用指定IP:Port,直接使用微服务名即可。

2.4 启动服务与测试

在IDEA中启动如下微服务:两个Order服务,三个Product服务,端口如下:

image-20250707161322793

然后在Nacos管理界面查看,服务已注册到Nacos了:

image-20250707161411743

最后,调用接口:

image-20250707161501626

测试成功。

2.5 小结

  • Nacos服务端版本也要适配,选择2.4.3版本;
  • 如果用Docker启动Nacos,不仅要暴露8848端口,还要暴露9848和9849端口;
  • 如果使用了代理,注意端口冲突;
  • 编程真好玩,一会儿不行一会儿行,代码都没改,玄学是吧;

3. 配置中心

Nacos还可以作为配置中心,即可以将程序配置放在Nacos统一管理。

3.1 引入依赖

首先引入配置中心依赖:

xml
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>${version}</version>
</dependency>

3.2 创建配置

然后在Nacos服务管理端创建配置:

image-20250707162903940

3.3 导入配置

然后在product的微服务application.properties中导入Nacos的配置文件:

properties
spring.config.import=nacos:product.properties
  • nacos:是前缀,表示导入Nacos的配置;
  • product.properties就是创建配置时的Data ID

3.4 使用配置

我们可以使用@ConfigurationProperties绑定配置:

java
@Component
@ConfigurationProperties(prefix = "product")
@Data
public class ProductProperty {
    private String name;
    private BigDecimal price;
    private Integer stock;
}

也可以使用@Value注入配置,如下:

java
@Value("${product.name}")
private String productName;

但是@Value默认不支持运行期动态更新,需要结合@RefreshScope注解实现动态刷新,例如:

java
@RestController
@RefreshScope
public class ProductController {

    @Value("${product.name}")
    private String productName;
}

3.5 测试

在product微服务中编写如下接口:

java
@RestController
@RefreshScope
public class ProductController {

    @Value("${product.name}")
    private String productName;

    @Resource
    private ProductProperty productProperty;

    @GetMapping("/product/{id}")
    public Product getProduct(@PathVariable("id") Long id){
        Product product = new Product();
        product.setId(id);
        product.setName(productProperty.getName() + id + "  " + productName);
        product.setPrice(productProperty.getPrice());
        product.setStock(productProperty.getStock());
        return product;
    }

}

测试结果如下:

image-20250707164036669

4. 配置隔离

配置隔离是指项目存在多种环境,如开发环境dev,测试环境test和生产环境prod,在不同环境下,配置的值是不同的。

并且,存在多套微服务,如order,product等,每套微服务可能都需要配置数据源datasource.properties,如何区分不同微服务的数据源?

在Nacos中,可以通过设置命名空间(namespace)和组(group)来进行配置隔离。

  • 命名空间(namespace)区分环境,例如dev、test、prod;
  • 组(group)区分微服务,例如order、product等;

首先在Nacos服务端管理界面创建命名空间:

image-20250707164713657

然后创建配置:

image-20250707170544311

在三个环境(dev、test、prod)都有相同的组,相同Data ID的配置文件,但是每个配置文件内容不同,例如:

properties
datasource.url=mysql:xxx[prod]
datasource.username=prod_user
datasource.password=prod_password
properties
datasource.url=mysql:xxx[test]
datasource.username=test_user
datasource.password=test_password

然后,在微服务中,针对不同的环境,创建三个不同的配置文件:

image-20250707170800183

application-dev.properties配置文件中的内容如下:

properties
spring.cloud.nacos.config.namespace=dev

spring.config.import[0]=nacos:datasource.properties?group=product
spring.config.import[1]=nacos:common.properties?group=product
  • group=product:指定group

application.properties中指定激活的配置文件:

properties
server.port=9003
spring.application.name=product-service

spring.profiles.active=prod

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

最后,编写接口查看生效的配置是哪个:

java
@Component
@ConfigurationProperties(prefix = "datasource")
@Data
public class DataSourceProperty {
    private String url;
    private String username;
    private String password;
}
java
@RestController
public class DataSourceController {

    @Resource
    private DataSourceProperty dataSourceProperty;

    @GetMapping("/datasource")
    public DataSourceProperty getDataSourceProperty(){
        return dataSourceProperty;
    }

}

通过修改不同的激活配置文件,测试结果不同:

image-20250707171337236