SpringCloud(十)SpringCloudAlibaba Nacos

一、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-service
  cloud:
    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-service
  cloud:
    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 中的接口方法


    @Autowired
    private 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> {

    @Autowired
    private ConfigurableEnvironment environment;

    @Override
    public 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 {

    @Autowired
    private StringEncryptor encryptor;

    @Test
    public 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> {


    @Autowired
    private EnvironmentManager environmentManager;

    @Autowired
    private StringEncryptor encryptor;


    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        for (String key : event.getKeys()) {
            // 获取value
            Object 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")
    @RefreshScope
    public 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站尚硅谷的老师们。 喜喜

文章参考: 芋道源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值