文章目录


一、Nacos 分布式配置

1、Nacos概念

Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。

Spring Cloud Alibaba Nacos Config 是 Config Server 和 Client 的替代方案,客户端和服务器上的概念与 Spring Environment 和 PropertySource 有着一致的抽象,在特殊的 bootstrap 阶段,配置被加载到 Spring 环境中。当应用程序通过部署管道从开发到测试再到生产时,您可以管理这些环境之间的配置,并确保应用程序具有迁移时需要运行的所有内容。Nacos 的获取和启动方式可以参考 Nacos 官网。

2、Nacos安装


  • Nacos官网文档:https://nacos.io/zh-cn/docs/quick-start.html
  • 下载Nacos:https://github.com/alibaba/nacos/releases/tag/1.3.2(推荐下载1.3.2的版本)

下载之后修改bin/startup.cmd,找到MODE,修改模式从集群修改为单击模式

set MODE="cluster"

修改为

set MODE="standalone"

双击startup.cmd则启动Nacos,直接访问提示的地址,默认账号密码都是nacos

【Spring Cloud Alibaba】Nacos 分布式配置_spring

我这里的访问地址就是:http://192.168.10.3:8848/nacos/index.html

【Spring Cloud Alibaba】Nacos 分布式配置_分布式_02

二、Nacos实战

1、搭建项目

项目名字设置为:spring-cloud-alibaba-learn,后面需要用到配置

使用官网提供的脚手架(https://start.aliyun.com/bootstrap.html),选择以下几个组件:


  • Nacos Config
  • Spring Web
  • Spring Boot Actuator
    【Spring Cloud Alibaba】Nacos 分布式配置_spring cloud_03

2、配置Nacos

在Nacos的命名空间增加一个空间配置:sandbox-configuration

并且新增配置,配置的DataID为:spring-cloud-alibaba-learn.properties

【Spring Cloud Alibaba】Nacos 分布式配置_java_04

然后编辑该配置,增加两个属性

【Spring Cloud Alibaba】Nacos 分布式配置_动态刷新_05

3、项目配置

修改bootstrap.properties文件

# 应用名称
spring.application.name=spring-cloud-alibaba-learn

# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
spring.cloud.nacos.config.username=nacos
spring.cloud.nacos.config.password=nacos
spring.cloud.nacos.config.contextPath=/nacos
# 设置配置中心服务端地址
spring.cloud.nacos.config.server-addr=localhost:8848
# Nacos 配置中心的namespace。需要注意,如果使用 public 的 namcespace ,请不要填写这个值,直接留空即可
spring.cloud.nacos.config.namespace=sandbox-configuration
spring.cloud.nacos.config.file-extension=properties

4、读取配置属性

package cn.tellsea;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import javax.annotation.PostConstruct;

/**
* @author Tellsea
* @date 2021/12/17
*/
@SpringBootApplication
public class SpringCloudAlibabaLearnApplication {

@Value("${user.name}")
private String userName;
@Value("${user.age}")
private int userAge;

@PostConstruct
public void init() {
System.out.printf("[init] user name : %s , age : %d%n", userName, userAge);
}

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

}

控制台输出以下信息,则表示配置完成了

[init] user name : Tellsea , age : 22

5、实现 Bean @Value 属性动态刷新

修改上一节的启动类,增加@RestController、@RefreshScope注解,并增加一个访问接口

package cn.tellsea;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;

/**
* @author Tellsea
* @date 2021/12/17
*/
@SpringBootApplication
@RestController
@RefreshScope
public class SpringCloudAlibabaLearnApplication {

@Value("${user.name}")
private String userName;
@Value("${user.age}")
private int userAge;

@PostConstruct
public void init() {
System.out.printf("[init] user name : %s , age : %d%n", userName, userAge);
}

@RequestMapping("/user")
public String user() {
return String.format("[HTTP] user name : %s , age : %d", userName, userAge);
}

@PreDestroy
public void destroy() {
// 这里可以观察到,修改了配置之后,调用了销毁的方法
System.out.printf("[destroy] user name : %s , age : %d%n", userName, userAge);
}

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

}

我们可以看到控制台一样你的输出信息,使用浏览器访问接口http://localhost:8080/user,同样的输出相同的配置

然后我们修改nacos的配置,将user.age=20,修改为user.age=99,然后再请求user接口,查看配置信息,已经是修改后的配置参数了。这里需要注意一点,这种方式刷新Bean,是通过销毁Bean重新初始化的方式,来实现属性值的修改

6、实现@ConfigurationProperties Bean 属性动态刷新

创建一个User的实体类

package cn.tellsea.nacosconfig;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;

/**
*
* @author Tellsea
* @date 2021/12/20
*/
@RefreshScope
@ConfigurationProperties(prefix = "user")
public class User {

private String name;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

修改启动类的配置

package cn.tellsea;

import cn.tellsea.nacosconfig.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
* @author Tellsea
* @date 2021/12/17
*/
@SpringBootApplication
@RestController
@RefreshScope
@EnableConfigurationProperties(User.class)
public class SpringCloudAlibabaLearnApplication {

@Value("${user.name}")
private String userName;
@Value("${user.age}")
private int userAge;

@Autowired
private User user;

@PostConstruct
public void init() {
System.out.printf("[init] user name : %s , age : %d%n", userName, userAge);
}

@RequestMapping("/user")
public String user() {
return String.format("[HTTP] user name : %s , age : %d", userName, userAge);
}

@RequestMapping("/user2")
public String user2() {
return "[HTTP] " + user;
}

@PreDestroy
public void destroy() {
System.out.printf("[destroy] user name : %s , age : %d%n", userName, userAge);
}


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

}

然后将nacos的配置的参数修改了,再访问user2的接口,一样的拿到了修改之后的Bean

[HTTP] User{name='Tellsea', age=99}

7、监听实现 Bean 属性动态刷新

package cn.tellsea;

import cn.tellsea.nacosconfig.User;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;

/**
* @author Tellsea
* @date 2021/12/17
*/
@SpringBootApplication
@RestController
@RefreshScope
@EnableConfigurationProperties(User.class)
public class SpringCloudAlibabaLearnApplication {

@Autowired
private User user;
@Autowired
private NacosConfigManager nacosConfigManager;

@Bean
public ApplicationRunner runner() {
return args -> {
String dataId = "spring-cloud-alibaba-learn.properties";
String group = "DEFAULT_GROUP";
nacosConfigManager.getConfigService().addListener(dataId, group, new
AbstractListener() {
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("[Listener] " + configInfo);
System.out.println("[Before User] " + user);
Properties properties = new Properties();
try {
properties.load(new StringReader(configInfo));
String name = properties.getProperty("user.name");
int age = Integer.valueOf(properties.getProperty("user.age"));
user.setName(name);
user.setAge(age);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("[After User] " + user);
}
});
};
}

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

}

观察日志输出结果

user.age=22, type=properties
[Listener] user.name=Tellsea
user.age=22
[Before User] User{name='Tellsea', age=99}
[After User] User{name='Tellsea', age=22}

8、Nacos提供了断点监控

配置文件中有以下断点监控信息

# Actuator Web 访问端口
management.server.port=8081
management.endpoints.jmx.exposure.include=*
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

访问http://127.0.0.1:8081/actuator,查看actuator所有监控点

【Spring Cloud Alibaba】Nacos 分布式配置_java_06访问http://127.0.0.1:8081/actuator/nacos-config,查看actuator所有监控点

【Spring Cloud Alibaba】Nacos 分布式配置_java_07

微信公众号

【Spring Cloud Alibaba】Nacos 分布式配置_动态刷新_08