Linux搭建Nacos及Nacos集群

2 篇文章 0 订阅
2 篇文章 0 订阅

为什么选择 spring-cloud-alibaba

在 spring-cloud 部分组件宣布闭源后,急需一套可以代替的开源框架,而 spring-cloud-alibaba 是对 Spring Cloud 的标准实现,以微服务为核心的整体解决方案

版本选择

各组件版本以官方公布的版本说明为准.

Nacos

什么是 Nacos

官方解读

简单来说,Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 服务端配置

预备环境

Nacos 依赖 Java 环境来运行。如果您是从代码开始构建并运行Nacos,还需要为此配置 Maven环境,请确保是在以下版本环境中安装使用:

  1. 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
  2. 64 bit JDK 1.8+;下载 & 配置
  3. Maven 3.2.x+;下载 & 配置

下载&安装

你可以通过源码和发行包两种方式来获取 Nacos。

从 Github 上下载源码方式

git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
ls -al distribution/target/

// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin

下载编译后压缩包方式

您可以从 最新稳定版本 下载 nacos-server-$version.zip 包。

  unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
  cd nacos/bin

nacos 配置数据库&更改默认账号密码

预备环境

mysql 5.7+(包含5.7)

创建 nacos 所需的表

nacos 解压后的文件夹中,conf 目录下 有一个文件叫做:nacos-mysql.sql,创建一个数据库,让后执行这个 sql 文件,结果如下图:

1643349523-1

修改配置

修改 nacos 安装文件夹下 conf目录中的::application.properties,改动如下:

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/你的数据库名称?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=你的数据库用户名
db.password.0=你的数据库密码
修改默认密码

下面开始改默认密码,创建一个 java 工程,为求方便最好是 springboot 工程,原因在于 nacos 的密码生成使用的是 spring-security 包下的 BCryptPasswordEncoder 类。

添加依赖

<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-security</artifactId>
</dependency>

写一个 main 方法

public static void main(String[] args) {
        String passWord = new BCryptPasswordEncoder().encode("123456");
        System.out.println(passWord);
}

或者使用在线生成的 如:Bcrypt生成(未试验),让后直接修改数据库,或者等服务启动成功后,再去页面修改密码即可.

单机启动&停止

  • 启动

    Linux/Unix/Mac

    启动命令(standalone代表着单机模式运行,非集群模式):

    sh startup.sh -m standalone
    

    如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

    bash startup.sh -m standalone
    
    Windows

    启动命令(standalone代表着单机模式运行,非集群模式):

    startup.cmd -m standalone
    
  • 停止

    Linux/Unix/Mac
    sh shutdown.sh
    
    Windows
    shutdown.cmd
    

    或者双击shutdown.cmd运行文件。

集群配置 & 启动、停止

预备环境,已经源码下载安装过程与单机一致,单机可以不配置数据库,但是集群一定要配置。

集群配置
端口详情

一个 nacos 服务启动 会用到三个端口号,在集群配置初期要做好端口规划,避免端口冲突,三个端口号详情以服务本身配置端口号为 8848为例:

端口号与主端口号的偏移量描述
88480nacos 服务本身端口号
98481000客户端 grpc 请求服务端端口,用于客户端向服务端发送连接和请求
98491001服务端 grpc 请求服务端端口,用于服务间同步等

由于我只有一台服务器,以下过程均是在一台服务器中配置,但过程类似

端口规划
主端口号客户端请求端口号服务端请求端口号描述
884898489849服务一
885898589859服务二
886898689869服务三
配置修改

首先将安装文件复制,或者解压三份,名称推荐以nacos+主端口号组合,如下图:

1643351805-1

  • nacos 服务配置修改

    修改 conf 目录下的 application.properties,三个服务都需要改成对应的端口号,如下图:

    1643352108-1

  • 集群文件配置修改

    复制 conf 目录下的 cluster.conf.example 文件,重命名为:cluster.conf,让后将每行配置成 ip:端口的格式,如下:

    官方示例

    [root@VM-4-7-centos conf]# cat cluster.conf.example 
    #
    # Copyright 1999-2021 Alibaba Group Holding Ltd.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    #
    
    #it is ip
    #example
    192.168.16.101:8847
    192.168.16.102
    192.168.16.103
    

    我的配置:

    [root@VM-4-7-centos conf]# cat cluster.conf
    #2022-01-27T17:23:54.963
    192.168.122.1:8848
    192.168.122.1:8858
    192.168.122.1:8868
    

    因为这个配置是所有的服务一致的,所以可以在 windows配置好,在上传到 Linux 上,每个服务都要有。

  • 启动脚本修改

    修改 nacos 安装目录下的 bin 目录下的 startup.sh 文件,若默认配置的内存过大,根据实际情况进行调整,下图为我修改之后的配置.

    image-20220218182515766

启动

分别执行三个文件夹,bin 目录下的 startup.sh 文件进行启动即可

sh startup.sh
停止

三个文件夹内,bin 目录下 执行 shutdown.sh 文件

sh shutdown.sh

Nacos 快速开始

创建项目

版本选择

当前 Spring Cloud Alibaba 的最新版本为 2.2.7.RELEASE ,因此 Spring Cloud 的版本选择为:Spring Cloud Hoxton.SR12,Spring Boot 的版本选择为:2.3.12.RELEASE

项目结构

1645079210-1

  • 父 POM

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://maven.apache.org/POM/4.0.0"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <modules>
            <module>learn-cloud-alibaba-nacos</module>
        </modules>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.12.RELEASE</version>
        </parent>
    
        <groupId>com.dran.cloud.learn</groupId>
        <artifactId>learn-cloud-alibaba</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>pom</packaging>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
            <spring.cloud.alibaba.version>2.2.7.RELEASE</spring.cloud.alibaba.version>
        </properties>
    
        <!--
        SpringCloud和SpringCloudAlibaba由于依赖过多,所以使用 dependencyManagement 来进行管理
        * 统一版本号
        * 只做声明,子模块不会自动引入全部依赖
        * 子模块声明了依赖,但未指定版本号和scope时,则会继承父项目的版本号和scope,否则覆盖.
        -->
        <dependencyManagement>
            <dependencies>
                <!--SpringCloud版本声明-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring.cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <!--SpringCloudAlibaba版本声明-->
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>${spring.cloud.alibaba.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    </project>
    
  • 子POM

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>learn-cloud-alibaba</artifactId>
            <groupId>com.dran.cloud.learn</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.dran.cloud.learn.nacos</groupId>
        <artifactId>learn-cloud-alibaba-nacos</artifactId>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                </plugin>
            </plugins>
    
        </build>
    </project>
    
服务发现
  1. 添加依赖

    		<!--服务注册/发现依赖-->
            <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-actuator</artifactId>
            </dependency>
    

    注: spring-boot-starter-actuator 这个依赖是用来监测服务是否正常

  2. application.yml

    server:
      port: 8081
    spring:
      application:
        #服务名称,服务注册到nacos上时默认也是使用这个名称
        name: cloud-nacos-servicec
      cloud:
        nacos:
          discovery:
            #nacos 地址
            server-addr: https://nacos.drancode.com
            #nacos开启权限验证后,配置用户名称
            username: nacos
            #nacos开启权限验证后,配置用户密码
            password: Longtao199606.
            #配置 命名空间
            namespace: public
            #自定义group
            group: 
    management:
      endpoints:
        web:
          exposure:
            include: '*'
      endpoint:
        health:
          show-details: always
    

    服务启动后,nacos截图:

    image-20220218182339312

  3. 关于 @EnableDiscoveryClient

    该注解在当前版本下不配置服务也能正常进行服务注册和服务发现

配置管理
properties 类型的配置文件
  1. 添加依赖

    		<!--nacos配置管理-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
    
  2. 配置修改

    nacos-config 使用 bootstrap.properties 或者 bootstrap.yml 来进行配置,与 application.properties 或者 application.yml 类似,具体区别可以自行考证

    DataId 默认使用 spring.application.name 配置跟文件扩展名结合(配置格式默认使用 properties), GROUP 不配置默认使用 DEFAULT_GROUP。因此该配置文件对应的 Nacos Config 配置的 DataId 为 cloud-nacos-service.properties, GROUP 为 DEFAULT_GROUP

    #服务名称
    spring.application.name=cloud-nacos-service
    #nacos服务地址
    spring.cloud.nacos.config.server-addr=
    #nacos用户名称
    spring.cloud.nacos.config.username=
    #nacos用户密码
    spring.cloud.nacos.config.password=
    
    
  3. 通过代码读取配置文件

    @SpringBootApplication
    @EnableDiscoveryClient
    public class CloudNacosApplication {
        public static void main(String[] args) {
            ConfigurableApplicationContext applicationContext = SpringApplication.run(CloudNacosApplication.class, args);
            String userName = applicationContext.getEnvironment().getProperty("user.name");
            String userAge = applicationContext.getEnvironment().getProperty("user.age");
            System.err.println("user name :"+userName+"; age: "+userAge);
        }
    }
    
  4. 创建配置文件

    Data Id 不带文件扩展名也可以,nacos也会匹配上,但是推荐还是带上文件扩展名

    image-20220218182709553

  5. 运行结果

    1645155109-1

配置 yml 类型的配置文件
  1. 添加依赖

    		<!--nacos配置管理-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
    
  2. 配置修改

    上面使用 bootstrap.properties 来进行配置,这次就用 yml 来进行配置

    spring:
      application:
        #服务名称
        name: cloud-nacos-service
      cloud:
        nacos:
          config:
            #nacos服务地址
            server-addr: 
            #nacos用户名称
            password: 
            #nacos用户密码
            username: 
            #指定配置文件的扩展名
            file-extension: yml
    
  3. 通过代码读取配置文件

    @SpringBootApplication
    @EnableDiscoveryClient
    public class CloudNacosApplication {
        public static void main(String[] args) {
            ConfigurableApplicationContext applicationContext = SpringApplication.run(CloudNacosApplication.class, args);
            String userName = applicationContext.getEnvironment().getProperty("user.name");
            String userAge = applicationContext.getEnvironment().getProperty("user.age");
            System.err.println("user name :"+userName+"; age: "+userAge);
        }
    }
    
  4. 创建配置文件

    1645163849-1

    Data Id 不带文件扩展名也可以,nacos也会匹配上

  5. 运行结果

    1645163927-1

动态更新

你可以通过配置 spring.cloud.nacos.config.refresh.enabled=false 来关闭动态刷新

  • 代码修改

    Nacos Config 默认支持配置的动态更新,启动 Spring Boot 应用测试的代码如下:

    @SpringBootApplication
    @EnableDiscoveryClient
    public class CloudNacosApplication {
        public static void main(String[] args) throws InterruptedException {
            ConfigurableApplicationContext applicationContext = SpringApplication.run(CloudNacosApplication.class, args);
            while(true) {
                //当动态配置刷新时,会更新到 Enviroment中,因此这里每隔一秒中从Enviroment中获取配置
                String userName = applicationContext.getEnvironment().getProperty("user.name");
                String userAge = applicationContext.getEnvironment().getProperty("user.age");
                System.err.println("user name :" + userName + "; age: " + userAge);
                TimeUnit.SECONDS.sleep(1);
            }
        }
    }
    
  • 运行结果

    1645164063-1

配置多环境配置文件

Nacos Config 在加载配置的时候,不仅仅加载了以 DataId 为 ${spring.application.name}.${file-extension:properties} 为前缀的基础配置,还加载了DataId为 ${spring.application.name}-${profile}.${file-extension:properties} 的基础配置。在日常开发中如果遇到多套环境下的不同配置,可以通过Spring 提供的 ${spring.profiles.active} 这个配置项来配置。 DataId 一定要带上文件扩展名.

${spring.profiles.active} 当通过配置文件来指定时必须放在 bootstrap.properties 文件中。
spring.profiles.active=dev
  • 新增Nacos配置文件

    1645168356-1

    1645168397-1

  • bootstrap.yml 修改

    spring:
      application:
        #服务名称
        name: cloud-nacos-service
      cloud:
        nacos:
          config:
            #nacos服务地址
            server-addr: 
            #nacos用户名称
            password: 
            #nacos用户密码
            username: 
            #指定配置文件的扩展名
            file-extension: yml
      profiles:
      	# 不同环境的标识
        active: dev
    
  • dev环境运行结果

    1645168142-1

  • prod环境运行结果

    spring.profiles.active 改为 prod

    1645168451-1

灵活切换

此案例中我们通过 spring.profiles.active=<profilename> 的方式写死在配置文件中,而在真正的项目实施过程中这个变量的值是需要不同环境而有不同的值。这个时候通常的做法是通过 -Dspring.profiles.active=<profile> 参数指定其配置来达到环境间灵活的切换。

配置 namespace

Nacos 内部有 Namespace 的概念:

用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

在没有明确指定 ${spring.cloud.nacos.config.namespace} 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespae。如果需要使用自定义的命名空间,可以通过以下配置来实现:

spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7
自定义 Group 配置

在没有明确指定 ${spring.cloud.nacos.config.group} 配置的情况下, 默认使用的是 DEFAULT_GROUP 。如果需要自定义自己的 Group,可以通过以下配置来实现:

spring.cloud.nacos.config.group=DEVELOP_GROUP

该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值一定要和 spring.cloud.nacos.config.group 的配置值一致。

自定义扩展 DataId

当出现配置文件名称与服务名称不一致,或者项目需要指定多个配置文件时,使用原先的默认服务名称+默认文件扩展名或者file-extension指定文件扩展名称方式无法满足,因此通过自定义 DataId 的方式来进行配置文件的指定.

自定义 DataId 的指定方式有两种, spring.cloud.nacos.config.extension-configsspring.cloud.nacos.config.shared-configs .

extension-configs
  • 配置

    spring.application.name=opensource-service-provider
    spring.cloud.nacos.config.server-addr=127.0.0.1:8848
    
    # config external configuration
    # 1、Data Id 在默认的组 DEFAULT_GROUP,不支持配置的动态刷新
    spring.cloud.nacos.config.extension-configs[0].data-id=ext-config-common01.properties
    
    # 2、Data Id 不在默认的组,不支持动态刷新
    spring.cloud.nacos.config.extension-configs[1].data-id=ext-config-common02.properties
    spring.cloud.nacos.config.extension-configs[1].group=GLOBALE_GROUP
    
    # 3、Data Id 既不在默认的组,也支持动态刷新
    spring.cloud.nacos.config.extension-configs[2].data-id=ext-config-common03.properties
    spring.cloud.nacos.config.extension-configs[2].group=REFRESH_GROUP
    spring.cloud.nacos.config.extension-configs[2].refresh=true
    

    可以看到:

    • 通过 spring.cloud.nacos.config.extension-configs[n].data-id 的配置方式来支持多个 Data Id 的配置。
    • 通过 spring.cloud.nacos.config.extension-configs[n].group 的配置方式自定义 Data Id 所在的组,不明确配置的话,默认是 DEFAULT_GROUP。
    • 通过 spring.cloud.nacos.config.extension-configs[n].refresh 的配置方式来控制该 Data Id 在配置变更时,是否支持应用中可动态刷新, 感知到最新的配置值。默认是不支持的。
  • 注意事项

    多个 Data Id 同时配置时,他的优先级关系是 spring.cloud.nacos.config.extension-configs[n].data-id 其中 n 的值越大,优先级越高。

    spring.cloud.nacos.config.extension-configs[n].data-id 的值必须带文件扩展名,文件扩展名既可支持 properties,又可以支持 yaml/yml。 此时 spring.cloud.nacos.config.file-extension 的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。

shared-configs
  • 配置

    # 配置支持共享的 Data Id
    spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml
    
    # 配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP
    spring.cloud.nacos.config.shared-configs[0].group=GROUP_APP1
    
    # 配置Data Id 在配置变更时,是否动态刷新,缺省默认 false
    spring.cloud.nacos.config.shared-configs[0].refresh=true
    

    可以看到:

    • 通过 spring.cloud.nacos.config.shared-configs[n].data-id 来支持多个共享 Data Id 的配置。
    • 通过 spring.cloud.nacos.config.shared-configs[n].group 来配置自定义 Data Id 所在的组,不明确配置的话,默认是 DEFAULT_GROUP。
    • 通过 spring.cloud.nacos.config.shared-configs[n].refresh 来控制该Data Id在配置变更时,是否支持应用中动态刷新,默认false。
  • 注意事项

    extension-configs 的注意事项相同

配置的优先级

Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置。

  • A: 通过 spring.cloud.nacos.config.shared-configs[n].data-id 支持多个共享 Data Id 的配置
  • B: 通过 spring.cloud.nacos.config.extension-configs[n].data-id 的方式支持多个扩展 Data Id 的配置
  • C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置

当三种方式共同使用时,他们的一个优先级关系是:A < B < C , 优先级大的会覆盖优先级小的,并且会形成互补,互补的意思是优先级小的配置文件配置了其他种类配置文件不存在的配置,那么最终加载的配置中该配置会保留.

profile > 默认配置文件 > extension-configs(下标越大优先级越大) > shared-configs(下标越大优先级越大)

配置的写法

除了默认的 数组下标 的写法外,yml还支持 - 的写法,例如:

spring:
  application:
    name: nacos-config
  cloud:
    nacos:
      server-addr: 
      username: 
      password: 
      config:
        file-extension: yml
        # 优先级比默认的低,如果重名不生效
        shared-configs:
          - dataId: order-service-shared-mysql.yml
            #默认是 DEFAULT_GROUP,可不写
          	group: DEFAULT_GROUP
            refresh: true
          - dataId: order-service-shared-mq.yml
          	#默认是 DEFAULT_GROUP,可不写
          	group: DEFAULT_GROUP
            refresh: true
        # 优先级比默认的低,但是比 shared 高
        extension-configs[0]:
          dataId: order-service-extension-matedata.yml
          #默认是 DEFAULT_GROUP,可不写
          group: DEFAULT_GROUP
          refresh: true
        extension-configs[1]:
          dataId: order-service-extension-param.yml
          #默认是 DEFAULT_GROUP,可不写
          group: DEFAULT_GROUP
          refresh: true

@RefreshScope 动态感知

当我们使用 如 @Value 或者 @ConfigurationProperties 等注解时,无法感知到参数值的变更,而通过 @RefreshScope 则能够进行动态刷新变量的值

示例代码

@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "mysql")
public class ParamConfig {
    private String name;
    @Value("${mq.name}")
    private String mqName;

    public String getName() {
        return name;
    }

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

    public String getMqName() {
        return mqName;
    }

    public void setMqName(String mqName) {
        this.mqName = mqName;
    }
}
@RestController
public class ParamController {
    @Autowired
    private ParamConfig paramConfig;

    @GetMapping("/getParam")
    public String getParam() {
        return "mysqlName:" + paramConfig.getName() +"=======" + "mqName:" + paramConfig.getMqName();
    }
}

使用常见的两种注入参数的方式

第一次运行,mysql.name 设置为 mqsql , mq.name 设置为 mq

运行结果:

image-20220221112436826

第二次运行,mysql.name 设置为 mqsql1 , mq.name 设置为 mq1

运行结果:

1645177764(1)

日志的变化:

1645177802(1)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值