Appearance
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控制台页面。

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服务,端口如下:

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

最后,调用接口:

测试成功。
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服务管理端创建配置:

3.3 导入配置
然后在product的微服务application.properties中导入Nacos的配置文件:
properties
spring.config.import=nacos:product.propertiesnacos:是前缀,表示导入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;
}
}测试结果如下:

4. 配置隔离
配置隔离是指项目存在多种环境,如开发环境dev,测试环境test和生产环境prod,在不同环境下,配置的值是不同的。
并且,存在多套微服务,如order,product等,每套微服务可能都需要配置数据源datasource.properties,如何区分不同微服务的数据源?
在Nacos中,可以通过设置命名空间(namespace)和组(group)来进行配置隔离。
- 命名空间(namespace)区分环境,例如dev、test、prod;
- 组(group)区分微服务,例如order、product等;
首先在Nacos服务端管理界面创建命名空间:

然后创建配置:

在三个环境(dev、test、prod)都有相同的组,相同Data ID的配置文件,但是每个配置文件内容不同,例如:
properties
datasource.url=mysql:xxx[prod]
datasource.username=prod_user
datasource.password=prod_passwordproperties
datasource.url=mysql:xxx[test]
datasource.username=test_user
datasource.password=test_password然后,在微服务中,针对不同的环境,创建三个不同的配置文件:

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=productgroup=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;
}
}通过修改不同的激活配置文件,测试结果不同:
