文章目录
- 一、Nacos 简介
-
- 1.1 为什么叫Nacos
- 1.2 Nacos 是什么?
- 二、 Nacos 下载安装
-
- 2.1 从github上面下载Nacos压缩包
- 2.2 Nacos 配置文件
- 三、Nacos 服务注册中心
-
- 3.1 引入CloudAlibaba的依赖
- 3.2 创建`sgg-alibaba-consumer80` 模块
- 3.3 创建Provider `sgg-alibaba-provider10001`
- 四、Nacos 配置中心
-
- 4.1 描述
- 4.2 创建`sgg-alibaba-client-config11001` 使用 Nacos 作为配置中心
- 4.3 EnvironmentChangeEvent 动态监听
- 4.4 配置加密
- 总结,感谢B站尚硅谷的老师们。 喜喜
一、Nacos 简介
1.1 为什么叫Nacos
Nacos 前四个字母分别为 Naming 和 Configuration 的前两个字母,最后的 s 为 Service
1.2 Nacos 是什么?
- 一个更易于构建云原生应用的动态服务发现,配置管理和服务管理平台
- Nacos: Dynamic Naming and Configuration Service
- 其实就是注册中心 + 配置中心的组合 等价于 Eureka + Config + Bus
二、 Nacos 下载安装
Nacos官网
Nacos 安装步骤
Nacos 下载地址
2.1 从github上面下载Nacos压缩包
下载之后解压缩, Nacos 目录文件
进入到 Bin 目录下有
我们通过 cmd 启动startup.cmd
可以看到 Nacos 是运行在 8848 端口下的。 我们访问 http://localhost:8848/nacos/index.html
Nacos 默认需要登录, 用户名 密码 都是 Nacos 。登录进去之后就是下面的页面
2.2 Nacos 配置文件
nacos/conf
是存放Nacos 配置文件的目录
三、Nacos 服务注册中心
3.1 引入CloudAlibaba的依赖
在顶级工程中 引入 CloudAlibaba
的依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.1.RELEASE</version><type>pom</type><scope>import</scope>
</dependency>
3.2 创建sgg-alibaba-consumer80
模块
引入 alibaba discovery 依赖
<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-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><groupId>cn.fllday</groupId><artifactId>sgg-api-common</artifactId><version>${project.version}</version>
</dependency>
配置yml文件
server:port: 80
spring:application:name: alibaba-consumer-servicecloud:nacos:discovery:server-addr: 127.0.0.1:8848 # nacos 服务地址service: ${
spring.application.name} # 注册到nacos的服务名,默认为 spring.application.name
spring.cloud.nacos.discovery.server-addr
nacos 服务注册地址
spring.cloud.nacos.discovery.service
服务注册到 nacos 的名称。 默认为 spring.application.name
创建启动类 AlibabaConsumer80App
@SpringBootApplication
@EnableDiscoveryClient
public class AlibabaConsumer80App {
public static void main(String[] args) {
SpringApplication.run(AlibabaConsumer80App.class, args);}
}
@EnableDiscoveryClient
开启 Spring Cloud 的注册发现功能。不过从 Spring Cloud Edgware 版本开始,实际上已经不需要添加 @EnableDiscoveryClient 注解,只需要引入 Spring Cloud 注册发现组件,就会自动开启注册发现的功能。例如说,我们这里已经引入了 spring-cloud-starter-alibaba-nacos-discovery 依赖,就不用再添加 @EnableDiscoveryClient 注解了。
在 Spring Cloud Common 项目中,定义了 DiscoveryClient 接口,作为通用的发现客户端,提供读取服务和读取服务列表的 API 方法。而想要集成到 Spring Cloud 体系的注册中心的组件,需要提供对应的 DiscoveryClient 实现类。
例如说,Spring Cloud Alibaba Nacos Discovery 提供了 NacosDiscoveryClient
实现,Spring Cloud Netflix Eureka 提供了 EurekaDiscoveryClient 实现。如此,所有需要使用到的地方,只需要获取到 DiscoveryClient 客户端,而无需关注具体实现,保证其通用性。
创建 controller
@RestController
@RequestMapping(value = "config")
@Slf4j
public class ConfigInfoController {
@Value("${server.port}")public String port;@RequestMapping(value = "echo")public String echo(String name){
log.info(" ================ [ {} : {} ] ===============", name, port);return name + ":" + port;}
}
启动 服务
可以看到控制台输出了我们的注册的服务名 以及 ip 地址和端口号
访问一下我们的接口 http:localhost/config/echo?name=gss
访问我们 Nacos 的控制页面,找到服务列表,可以看到我们的服务已经注册到我们的 Nacos 中了
3.3 创建Provider sgg-alibaba-provider10001
引入依赖 pom.xml
<dependencies><dependency><groupId>cn.fllday</groupId><artifactId>sgg-api-common</artifactId><version>${project.version}</version></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-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
</dependencies>
配置 application.yml
文件
server:port: 10001
spring:application:name: alibaba-provider-servicecloud:nacos:discovery:service: ${
spring.application.name} # 服务注册到nacos的服务名server-addr: 127.0.0.1:8848 # nacos 地址
创建启动类 AlibabaProvider10001App .java
@SpringBootApplication
@EnableDiscoveryClient
public class AlibabaProvider10001App {
public static void main(String[] args) {
SpringApplication.run(AlibabaProvider10001App.class, args);}
}
创建接口 ConfigInfoController .java
@RestController
@Slf4j
@RequestMapping(value = "config")
public class ConfigInfoController {
@Value("${server.port}")private String port;@Value("${spring.application.name}")private String applicationName;@GetMapping(value = "server")public String server(){
log.info("====================[ {},{} ]=================", applicationName, port);return applicationName + " : "+ port;}
}
修改sgg-alibaba-consumer80
使用 feign 远程调用 provider 服务 实现负载均衡
引入 openfeign 依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
实现远程调用 provider
@Component
@FeignClient(value = "alibaba-provider-service")
public interface ConfigRemoteService {
@GetMapping(value = "/config/server")String getProviderConfig();
}
添加Controller 中的接口方法
@Autowiredprivate ConfigRemoteService configRemoteService;@RequestMapping(value = "remoteInfo")public String remoteInfo(){
return configRemoteService.getProviderConfig();}
增加 EnableFeignClients
注解在启动类上 。 。
启动 10001 服务, alibaba 80 服务
启动 10001 的时候,我们使用 idea 启动两个 ,一个正常运行启动类就可以了 。 另一个 选择编辑配置
取名字为 AlibabaProvider10001App Copy 注意名字不可以重复
最后运行我们的 alibaba 80 服务。
访问我们nacos 主页 查看服务列表
可以看到我们的 provider 有两台实例, consumer 有一台实例。 我们访问接口 http://localhost/config/remoteInfo
在服务列表中有一个 DEFAULT_GROUP 是实例的群组,还有个 NAMESPACE 是命名空间。 可以做服务隔离的。 有兴趣的自己研究一下下哈哈。
四、Nacos 配置中心
4.1 描述
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 环境中。当应用程序通过部署管道从开发到测试再到生产时,您可以管理这些环境之间的配置,并确保应用程序具有迁移时需要运行的所有内容
4.2 创建sgg-alibaba-client-config11001
使用 Nacos 作为配置中心
引入依赖
pom.xml
<dependencies><dependency><groupId>cn.fllday</groupId><artifactId>sgg-api-common</artifactId><version>${project.version}</version></dependency>
<!-- Nacos 配置 中心依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency>
<!-- Nacos 服务注册依赖--><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-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies>
创建 bootstrap.yml
文件配置
server:port: 11001
spring:application:name: alibaba-client-config-service # 服务名称cloud:nacos:discovery:server-addr: ${
nacos.ip}service: ${
spring.application.name}config:group: DEFAULT_GROUP # 默认 分组namespace: # 使用nacos的默认的命名空间name: ${
spring.application.name}file-extension: yaml # 使用nacos 配置集中的 dataId 的文件拓展名,同时也是 Nacos 的配置集 的配置个格式,默认为 properties
nacos:ip: 127.0.0.1:8848
server-addr
:客户端获取 配置的 地址 nacos 服务地址
namespace
: 使用 nacos 命名空间 , 默认为 Null 。 表示使用 public 这个默认的命名空间
命名空间: 进行租户粒度的配置隔离,不同的命名空间下,可以存在相同的 Group 或者 Data ID 的配置, Namespace 的常用场景之一就是不同环境的配置的区分隔离。 例如开发测试环境和生产环境的资源
group
配置项, 使用 Nacos 的配置分组。 默认为 DEFAULT_GROUP
Nacos 中的一组配置集,是组织配置的维度之一, 通过一个有意义的字符串(如 Buy 或者 Trade) 对配置集进行分组,从而区分DataID相同的配置及,当您 Nacos 创建一个配置时, 如果未填写配置分组的名称,则配置分组的名称默认采用
DEFAULT_GROUP
, 配置分组的场景场景,不同的应用或组件使用了相同的配置类型。 如database_url
或者MQ_topic
name
: 使用 Nacos 配置集的 DataID, 默认为 ${spring.application.name} - ${spring.profiles.active} - ${spring.cloud.nacos.configfile-extension}
file-extension
: 使用Nacos配置集中的 dataId 的拓展名。 同事也是 Nacos 配置的默认格式。 默认为 properties
根据我们上面的配置在Nacos 中添加我们的配置集
我们在 public 的命名空间下 点击 + 创建配置
配置Data ID 为 alibaba-client-config-service.yaml
, Group 为 DEFAULT_GROUP
, 配置内容:
config:info: 1937
点击发布。 就可以在配置列表中看到我们的配置了
创建 启动类 , 并添加一个获取一个
@SpringBootApplication
@EnableDiscoveryClient
public class AlibabaClientConfig11001App {
public static void main(String[] args) {
SpringApplication.run(AlibabaClientConfig11001App.class, args);}@RestController@Slf4j@RequestMapping(value = "config")@RefreshScope // 可以动态刷新配置中心的配置public static class ConfigController{
@Value("${config.info}")private String info;@GetMapping(value = "/getConfigInfo")public String getConfigInfo(){
return info;}}
}
启动 main 方法, 访问接口 http://localhost:11001/config/getConfigInfo
可以看到我们的接口是可以拿得到 Nacos 配置中心的具体配置。 我们现在将 Nacos 配置中心的 config.info 修改为1973
再重新访问我们的接口
可以看到,Nacos 是支持动态刷新的。 比SpringCloud Bus 消息总线好多了 _ O(∩_∩)O哈哈~
4.3 EnvironmentChangeEvent 动态监听
通过 @ConfigurationProperties
或者 @Value
+ @RefreScope
注解 , 已经能够满足我们绝大多数场景下的自动刷新配置的功能。 但是一些场景下,我们仍然需要实现对配置的监听,执行自定义的逻辑。
例如说: 当数据库连接的配置发生变化,我们需要通过监听该配置的变更新,重新初始化应用中的数据库连接。 从而访问到新的数据库地址
或者 当日志级别发生变化时,我们需要通过监听该配置的变更,设置应用中的 Logger 级别。
在SpringCloud 中 在 Environment 的属性发生变化时,会发布 EnvironmentChagneEvent 事件, 我们只需要实现 EnvironmentChangeEvent 事件的监听器, 就可以自定义逻辑实现
创建监听类
@Component
@Slf4j
public class NacosConfigEnvironmentChangeListener implements ApplicationListener<EnvironmentChangeEvent> {
@Autowiredprivate ConfigurableEnvironment environment;@Overridepublic void onApplicationEvent(EnvironmentChangeEvent event) {
Set<String> keys = event.getKeys();keys.forEach( k -> {
log.info("======== opApplicationEvent, key:[ {} ], 最新 value : [ {} ]========", k, environment.getProperty(k));});}
}
重启服务。 然后修改 Nacos 配置集的配置
可以看到后台打印的日志
2020-09-16 22:47:29.576 INFO 17364 --- [-localhost_8848] f.l.NacosConfigEnvironmentChangeListener : ======== opApplicationEvent, key:[ config.info ], 最新 value : [ 13213213213 ]========
4.4 配置加密
考虑到安全性, 我们可能会将配置文件中的敏感信息进行加密, 比如说 Mysql 的用户名密码, 第三方平台的 token 令牌等等。 不过 Nacos 暂时未内置加密的功能。
依旧是修改我们的 sgg-alibaba-client-config11001
引入依赖 pom.xml
<!-- 实现对 Jasypt 实现自动化配置 -->
<dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.2</version>
<!--<scope>test</scope>-->
</dependency>
配置 Nacos 配置集
这里为了测试简单,直接添加秘钥在 Nacos 配置中。实际建议加密秘钥和配置隔离。
配置文件 bootstrap.yml
不做改变
使用测试类。将配置项的值进行加密,代码如下
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AlibabaClientConfig11001App.class)
public class JasyptTest {
@Autowiredprivate StringEncryptor encryptor;@Testpublic void encode(){
String password = "woshimima";System.out.println(encryptor.encrypt(password) + "_____________________________________");password = "wobushimima";System.out.println(encryptor.encrypt(password) + "_________________________________________");}
}
加密结果
RAjV1g3q78pg0IpRoZvZNnY+F5iJvFszLgto53UYGgw=_____________________________________
JlVxzVlskl9TYXgVvD6L3s3+TbS5UBtlWmqbgogIgMQ=_________________________________________
我们将加密结果放入到 Nacos 配置集中 alibaba-client-config-service.yaml
切记使用 ENC() 包裹住 加密后的信息。
配置 JasyptEnvironmentChangeListener
针对 Jasypt 并未对 Nacos 自动配置刷新获取到的最新配置进行解密。 我们可以通过 JasyptEnvironmentChangeListener 监听器。 发现变更的配置项的值,是使用 Jasypt 进行加密。 则进行解密。 并设置到Environment 中
@Component
@Slf4j
public class JasyptEnvironmentChangeListener implements ApplicationListener<EnvironmentChangeEvent> {
@Autowiredprivate EnvironmentManager environmentManager;@Autowiredprivate StringEncryptor encryptor;@Overridepublic void onApplicationEvent(EnvironmentChangeEvent event) {
for (String key : event.getKeys()) {
// 获取valueObject val = environmentManager.getProperty(key);if (!(val instanceof String)) {
continue;}String encodeVal = (String) val;// 判断是否为加密, 如果是, 则进行解密if (((String) val).startsWith("ENC(") && ((String) val).endsWith(")")) {
String decodeStr = encryptor.decrypt(StringUtils.substringBetween(encodeVal, "ENC(", ")"));log.info("[onApplicationEvent] [key ({}), 解密后为 {}]", key, encodeVal);environmentManager.setProperty(key, decodeStr);}}}
}
修改 config/getConfigInfo
@RestController@Slf4j@RequestMapping(value = "config")@RefreshScopepublic static class ConfigController{
@Value("${config.info}")private String info;@Value("${config.woshimima}")private String woshimima;@Value("${config.wobushimima}")private String wobushimima;@GetMapping(value = "/getConfigInfo")public JSONObject getConfigInfo() {
JSONObject json = new JSONObject();json.put("woshimima", woshimima);json.put("wobushimima", wobushimima);json.put("info", info);return json;}}
重启服务。 访问我们的接口
可以看到。他在重启之后对这个加密信息进行解密了/。
总结,感谢B站尚硅谷的老师们。 喜喜
文章参考: 芋道源码