config_configure - CSDN
精华内容
参与话题
  • 【TP5.1】Config的用法

    千次阅读 2018-11-03 19:03:07
    需要读取某个一级配置的所有配置参数,可以使用 ...use Config;   使用助手函数:   config('app.name') config('app.');   这种类型的使用app.     这种类型的使用.code即可  ...

    需要读取某个一级配置的所有配置参数,可以使用

    需要引入

    use Config;

     

    使用助手函数:
     

    config('app.name')
    config('app.');

     

    这种类型的使用app.

     

     

    这种类型的使用.code即可

     

    展开全文
  • Config了解与使用

    2020-08-21 21:18:06
    Spring Cloud Config分布式配置中心分布式系统面临的配置文件问题Spring Cloud Config 简介可以做的操作服务端配置与测试新建模块配置读取客户端配置与测试Config动态刷新(手动版)动态版 分布式系统面临的配置文件...

    分布式系统面临的配置文件问题

           微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的!

    SpringCloud 提供了 ConfigServer 来解决这个问题,我们每一个微服务自己带着一个 application.yml ,上百个配置文件的管理…

    Spring Cloud Config 简介

           Spring Cloud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。

    在这里插入图片描述

    上图所示,假如有三个配置文件,然后每一个配置文件都连接了数据库(同一个),这个时候如果我要换一个数据库使用,那么就要将所有配置文件中的配置进行替换,这个时候我们就可以使用 Config Server 来进行统一配置,这样在我们管理的时候也会比较简单!

    Spring Cloud Config 分为服务端和客户端两部分。

    服务端 也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密 信息等访问接口。

    客户端 则是通过指定的配置中心来管理应用的资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载信息配置服务器默认采用 git 来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过 git 客户端工具来方便的管理和访问配置内容。

    可以做的操作

    1. 集中管理配置文件
    2. 不同环境不同配置,动态化的配置更新,分环境部署比如 dev/test/prod/beta/release
    3. 运行期间动态调整配置,不在需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉去配置自己的信息。
    4. 当配置发生改变的时候,服务不需要重启即可感知到配置文件的变化并且应用新的配置
    5. 将配置信息以 REST 接口的形式暴露(post、curl 访问刷新均可)

    由于 Spring Cloud Config 默认使用 Git 来存储配置文件(也有其它方式,比如支持 SVN 和 本地文件),但最推荐的还是 Git,而且使用的是 http/https 访问的形式!

    服务端配置与测试

    1. 在 github上创建一个名为 spring-cloud-config 的仓库

      在这里插入图片描述

    2. 将创建好的 git 仓库配置在本地

      使用 git clone 命令将 git 仓库下载下来

      git clone "自己的仓库地址"
      

      仓库地址:

      在这里插入图片描述

    3. 新建以下三个文件

      config-dev.yaml

      config:
        info: master branch,springcloud-config/config-dev.yaml version=1
      

      config-prod.yaml

      config:
        info: master branch,springcloud-config/config-prod.yaml version=1
      

      config-test.yaml

      config: 
        info: master branch,springcloud-config/config-test.yaml version=1
      

      然后将这三个文件全部放进下载的本地仓库中

      在这里插入图片描述

      文件的名字一定不要乱取,要安装官网的规则来定

    4. 输入以下命令将命令将新建的文件上传至 git 仓库

      4.1:进入配置好的本地仓库中

      在这里插入图片描述

      4.2:查看工作目录和暂存区的状态

      在这里插入图片描述

      这里我们就可以看到我们刚才放进去的三个新的文件

      4.3:使用 git add --all 提交未跟踪、修改和删除文件

      在这里插入图片描述

      4.4:这一步是第一次使用该仓库时需要进行的操作

      //获取git邮箱
      git config --global user.email "git邮箱"
      
      //获取git账号名
      git config --global user.name "git用户名"
      

      在这里插入图片描述

      这里需要注意的是,这里填写的邮箱和用户名都必须和 github 中的一致

      4.5:再次执行 git commit -m “init yaml”

      在这里插入图片描述

      4.6:提交数据至 github 仓库

      在这里插入图片描述

      4.7:查看是否提交成功

      在这里插入图片描述

      刚开始创建好项目的时候,只有一个 .md 文件,当我们提交成功之后就会把我们的文件存入仓库中

    新建模块

    创建一个名为 cloud-config-center-3344 的服务(这个服务就相当于 Config Server)

    修改 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>SpringCloud2020</artifactId>
            <groupId>com.lyang.springcloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>cloud-config-center-3344</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-config-server</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <!-- 引入自己定义的api通用包,可以使用 Payment 支付 Entity -->
            <dependency>
                <groupId>com.lyang.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>1.0-SNAPSHOT</version>
                <scope>compile</scope>
            </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>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    编写 yml 配置文件

    server:
      port: 3344
    
    spring:
      application:
        # 注册进 eureka 服务器的微服务名
        name: cloud-config-center
      cloud:
        config:
          server:
            git:
              # 自己的 github 仓库地址
              uri: https://github.com/T257ymq/spring-cloud-config.git
              # 搜索目录
              search-paths:
                - spring-cloud-config
          # 读取分支
          label: master
    
    # 服务注册到 eureka 地址
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:7001/eureka
    

    编写主启动类

    /**
     * 3344启动类
     * @EnableConfigServer:启用配置服务器
     */
    @SpringBootApplication
    @EnableConfigServer
    public class ConfigCenterMain3344 {
        public static void main(String[] args) {
            SpringApplication.run(ConfigCenterMain3344.class, args);
        }
    }
    

    配置读取

    方式一:/{lobel}/{application}-{profile}.yaml(推荐)

    在这里插入图片描述

    这种方式可以指定分支进行访问

    方式二:/{application}-{profile}.yml

    在这里插入图片描述

    这种方式没有指定分支的路径使用,所以就会直接使用默认的分支进行访问!

    方式三:/{application}-{profile}[/{label}]

    在这里插入图片描述

    这种方式的话需要我们自己去解析它里面的内容

    属性说明

    label:分支(branch)

    name:服务名

    profiles:环境(dev/test/prod)

    客户端配置与测试

    创建一个名为 cloud-config-client-3355 的子工程

    修改 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>SpringCloud2020</artifactId>
            <groupId>com.lyang.springcloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>cloud-config-client-3355</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <!-- 引入自己定义的api通用包,可以使用 Payment 支付 Entity -->
            <dependency>
                <groupId>com.lyang.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>1.0-SNAPSHOT</version>
                <scope>compile</scope>
            </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>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    编写 bootstrap.yml 文件

    server:
      port: 3355
    
    spring:
      application:
        name: config-client
      cloud:
        # Config 客户端配置
        config:
          # 分支名称
          label: master
          # 配置文件名称
          name: config
          # 读取后缀名称
          profile: dev
          # 配置中心地址
          uri: http://localhost:3344
    
    # 服务注册到 Eureka 地址
    eureka:
      client:
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka
    

    label、name、profile综合: master 分支上 config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yaml

    这里与之前有所不同,因为这里使用的是 bootstrap 格式的命名方式,而我们在前面使用的都是application 的命名方式来编写配置文件!

    Spring Cloud 会创建一个 “Bootstrap Context”,作为 Spring 应用的 Application Context 的父上下文。初始化的时候 Bootstrap Context 负责从外部源加载配置属性并解析配置,这两个上下文共享一个从外部获取的 Environment。

    bootetrap.yml 文件的优先级比 application.yml 文件要高!

    使用这个文件主要是为了更好的配置加载顺序和分级管理!

    3355 不会直接连接到git仓库,而是通过 3344 服务间接性的连接到!

    注意: 这个文件虽然名称不同,但是也是放在 resources 文件夹下的!

    编写启动类

    @SpringBootApplication
    @EnableEurekaClient
    public class ConfigClientMain3355 {
        public static void main(String[] args) {
            SpringApplication.run(ConfigClientMain3355.class, args);
        }
    }
    

    编写业务类

    @RestController
    @Slf4j
    public class ConfigClinetController {
        @Value("${config.info}")
        private String configInfo;
    
        @GetMapping(value = "/configInfo")
        public String getConfigInfo(){
            return configInfo;
        }
    }
    

    测试

    启动顺序:7001–3344–3355

    我们先来看一下 Eureka 中注册进来的服务

    在这里插入图片描述

    可以发现,3344 和 3355 都已经在注册中心里了!

    然后我们在来看一下 3344 是否能够正常执行
    在这里插入图片描述

    http://config-3344.com:3344/master/config-dev.yaml

    最后我们再来测试 3355 的效果

    在这里插入图片描述

    我们可以发现,3344 读取到的内容,在 3355 中也可以正常的获取到

    以上完成后,虽然 3355 中已经可以通过 3344 获取到了 git 仓库中某个环境的信息,但是如果这个时候我们更新了 git 仓库中的某一个环境版本,那么还能获取到吗?接下来我们就来看一下

    我们先把 git 仓库中的 dev 环境版本改变为 2

    在这里插入图片描述

    在这里插入图片描述

    然后在使用刚才测试的两个路径进行访问

    http://config-3344.com:3344/master/config-dev.yaml

    在这里插入图片描述

    http://localhost:3355/configInfo

    在这里插入图片描述

    我们可以发现,3344 执行的时候可以直接获取到仓库中最新的数据,而3355 的话就无法获取到最新的数据!除非自己重启或重新加载,这样非常的麻烦,所以我们接下来就来解决这个动态刷新的问题。

    Config动态刷新(手动版)

    避免每次更新配置都要重启客户端微服务(3355)

    先启动服务:7001–3344-3355

    实现步骤:

    1. 在 3355 服务的pom文件中引入 actuator 监控

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

      我们在之前已经导入了,这里大家了解一下即可

    2. 修改 3355服务中的 yml 文件,暴露监控端口

      server:
        port: 3355
      
      spring:
        application:
          name: config-client
        cloud:
          # Config 客户端配置
          config:
            # 分支名称
            label: master
            # 配置文件名称
            name: config
            # 读取后缀名称
            profile: dev
            # 配置中心地址
            uri: http://localhost:3344
      
      # 服务注册到 Eureka 地址
      eureka:
        client:
          service-url:
            defaultZone: http://eureka7001.com:7001/eureka
      
      # 暴露监控端点
      management:
        endpoints:
          web:
            exposure:
              include: "*"
      
    3. 为 3355 的 controller 类加上 @RefreshScope 注解

      /**
       * @RefreshScope:帮助我们做局部的参数刷新
       */
      @RestController
      @Slf4j
      @RefreshScope
      public class ConfigClinetController {
          @Value("${config.info}")
          private String configInfo;
      
          @GetMapping(value = "/configInfo")
          public String getConfigInfo(){
              return configInfo;
          }
      }
      
    4. 测试

      我们在按照刚才的方式进行测试,首先修改 git 仓库中的某个数据,然后测试方法

      这里我们就修改 test 环境的版本号

      在这里插入图片描述

      这里需要注意修改完后再去修改 bootstrap 文件中的指定环境,如下

      server:
      port: 3355
      
      spring:
      application:
       name: config-client
      cloud:
       # Config 客户端配置
       config:
         # 分支名称
         label: master
         # 配置文件名称
         name: config
         # 读取后缀名称
         # 上述3个综合:master 分支上 config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yaml
         profile: test
         # 配置中心地址
         uri: http://localhost:3344
      
      # 服务注册到 Eureka 地址
      eureka:
      client:
       service-url:
         defaultZone: http://eureka7001.com:7001/eureka
      
      # 暴露监控端点
      management:
      endpoints:
       web:
         exposure:
           include: "*"
      

      不进行修改的话就无法正确的查看对应信息!

      http://config-3344.com:3344/master/config-dev.yaml

      在这里插入图片描述

      http://localhost:3355/configInfo

    在这里插入图片描述

    这次我们就可以发现,似乎配置了这些东西之后 3355 还是不能解决之前出现的问题,还是需要重启才能获取到最新的数据,其实配置好这些东西之后我们还需要使用命令行的方式告诉它我们已经修改了数据,然后它才可以正常的获取到最新的数据!

    使用 win+R 输入 cmd 打开命令行页面输入以下命令通知客户端数据已经更新

    curl -X POST "http://localhost:3355/actuator/refresh"
    

    在这里插入图片描述

    执行完后我们再来进行测试查看效果

    在这里插入图片描述

    现在的话我们就已经可以正常获取到最新的数据啦。当然,如果以后想要获取最新的数据的话还是需要在此输入命令或者重启项目才能正常生效! 但是这种方式比重启服务要好很多。

    注意: 如果在下一次改变仓库数据后直接执行的话也是不能正常获取到数据的!!!

    动态版

    手动版比较适合用于少量服务的使用,并不适合大量服务的时候,因为大量服务就算弄个脚本也稍微有一点麻烦!

    但是如果是依靠 Config 本身想要实现动态刷新的话暂时还是做不到的,所以下一章会教大家使用 Spring Cloud Bus 的方式来进行动态刷新。

    展开全文
  • 一、引言在项目过程中,难免会需要一个方便的配置文件读写类,它可以像游戏的存档文件一样,记录着我们当前项目的配置信息,以至于方便我们每次初始化运行的时候可以从这个配置文件读取上一次的配置信息,当然也可以...

    一、引言

    在项目过程中,难免会需要一个方便的配置文件读写类,它可以像游戏的存档文件一样,记录着我们当前项目的配置信息,以至于方便我们每次初始化运行的时候可以从这个配置文件读取上一次的配置信息,当然也可以在程序运行过程中记录用户的配置设置信息。

    我们理想中的这个配置文件读写类,它要有以下这些方法:

    1. 支持读入一个指定配置文件的能力

    2. 支持随时加入一个配置项的能力

    3. 足够强大,能够写入各种数据结构的配置信息

    满足以上条件的配置文件读写类才是我们想要的。这篇博客显然不是一步一步介绍如何写出这样一个类的文章(这不是一件容易的事情,即使写出来也会千疮百孔),而是一篇在网上已有的流传久远的一个短小精悍的配置文件 Config 读写类的基础上的解读分析文章。

    我找到的这个短小精悍的配置文件 Config 读写类是来自于这篇博客:
    C++编写Config类读取配置文件

    这篇博客的作者仅仅粘贴出了这个 Config 类的代码以及简简单单的几行测试代码,对于大多数新手来说并不友好,因此我特意在阅读了相关代码并且自行建立测试项目进行了测试之后,萌发了想要写一篇博客来好好解读这个 Config 类的原理和用法的想法。

    由于不喜欢在博客里面大篇幅的粘贴代码,因此想要获取到这个配置文件 Config 读写类的同学可以在我的 GitHub 上阅读这个类(也就简简单单三个文件:一个 Config.h,另一个是 Config.cpp,testconfig.cpp 则是用来测试的文件而已):
    wangying2016/Config

    那么接下来,就让我们一步一步分析这个配置文件 Config 读写类的设计与实现吧!

    二、Config 设计之:数据结构

    要想了解一个类的设计与实现,最好的方法就是去了解它的设计目标,即需要满足的需求。

    这里我们需要了解的就是,一个配置文件的内容究竟是什么样子的:

    config contents

    由上图可知,我们的一个配置文件,是由两部分组成的:

    1. 注释内容:在示例文件中是由 # 来单行注释表示的,用来解释一些必要内容

    2. 配置项内容:配置内容其实就是一个一个的键值对的记录,左侧是 key 值,比如这里的 name 值,右侧是 value 值,对应这里的 wangying。而在键值对中间,间插了一个符号 =(当然可以自定义的)来分割 key 值和 value 值。

    可知,其实配置文件的内容是非常简单明了的。接下来,我们则需要将这种看似简单的文件结构抽象成我们熟悉的程序设计领域的数据结构。

    如果你学过主流编程语言的话,这里的键值对应该会让你想起那么几个词:
    maphashdictionary 等等
    在程序员的世界里,键值对其实就是我们的映射。比如在 C++ 里,我们要存储这样的数据就使用 std::map 即可。

    也就是说,我们的 Config 类中,需要有一个最基本最基本的存储配置文件键值对信息的 std::map 成员,这个成员用来将配置文件中的每个 key 值和其对应的 value 值记录下来。

    那么另外一个问题也就来了,我们的 std::map 究竟应该是什么类型的呢?

    哈哈,这个问题其实非常简单,因为我们的键值对信息都是要读出写入到文件的,那么 std::map 不论是 key 值还是 value 值都将会是字符串类型,即 C++ STL 的 std::string (Config 类不支持中文编码)类即可。

    那么有人就会问了,如果 value 值只是一个简简单单的 std::string 类的话,我想要存储一个非常复杂的数据结构怎么办,比如一个 phone key 值,对应了一个电话号码列表呢?

    这个问题其实也非常简单,这里的 std::map 成员只是 Config 类中的最基本最基本存储到文件里的字符串键值对记录,而 Config 为了支持用户存储多种复杂的 value 值,还提供了模板支持。因此,这里只需要你提供的 value 值的结构可以被转化为 std::string 类型,就可以使用 Config 类来存储你的数据结构了。

    因此,让我们看看 Config 类的代码:

    std::string m_Delimiter;  //!< separator between key and value  
    std::string m_Comment;    //!< separator between value and comments  
    std::map<std::string, std::string> m_Contents;  //!< extracted keys and values  

    这三个内部的属性, m_Delimiter 是我们之前提到的 key 值和 value 值的分隔符 = 的设置,m_Comment 是我们之前提到的注释内容开头 # 字符的设置,m_Contents 就是我们上面讨论的 std::map 对象,并且以 key 值和 value 值均为 std::string 类型存储。

    此外,我们在 Config 类中看到的那么多的模板函数,其归根结底想要实现的,就是支持用户自定义的 value 数据结构的读取和写入:

    //!<Search for key and read value or optional default value, call as read<T>  
    template<class T> T Read(const std::string& in_key) const;  
    // Modify keys and values  
    template<class T> void Add(const std::string& in_key, const T& in_value);

    这里截取了两个重要的函数,一个用来读取 key 值对应的 value 值,一个用来添加一个键值对。可以看到,这里的 key 值永远都是一个 std::string 类型的对象,而相应的 value 值则是模板定义的类型,支持用户自定义传入任何的可以转成 std::string 类型的数据结构。

    三、Config 设计之:暴露方法

    接下来让我们想想这样一个问题,在我们看到了配置文件的内容之后,并且将其抽象成了 std::map 的数据结构,之后我们需要做的,就是给类的调用者暴露方法的方法即可。

    那么应该有哪些方法呢:

    1. 一个可以跟某个具体的配置文件绑定起来的构造函数

    2. 获取指定 key 值的 value 值

    3. 加入一对键值对

    4. 修改指定 key 值的 value 值

    5. 删除一对键值对

    暂时就想到了这些比较重要的,那么 Config 类中提供了这些方法了吗?

    哈哈,提供了,让我们一个一个来看:

    1. 一个可以跟某个具体的配置文件绑定起来的构造函数

    Config::Config(string filename, string delimiter, string comment)
        : m_Delimiter(delimiter), m_Comment(comment)
    {
        // Construct a Config, getting keys and values from given file  
        std::ifstream in(filename.c_str());
        if (!in) throw File_not_found(filename);
        in >> (*this);
    }

    作者使用 std::ifstream 打开了一个本地文件,注意,调用这个方法之前必须保证该文件存在。我们要注意到作者调用了 in >> (*this),调用了本类的 operator>> 重载函数,用来读取文件内容(此函数过于冗长,可以自行查看源码)并将其存储到 std::map

    //!<Search for key and read value or optional default value, call as read<T>  
    template<class T> T Read(const std::string& in_key) const;  
    template<class T> T Read(const std::string& in_key, const T& in_value) const;
    template<class T> bool ReadInto(T& out_var, const std::string& in_key) const;

    这三个都是模板函数,主要是用来获取用户自定义数据结构的 value 值。需要注意的是,这三个函数的用法,第一个是返回 value 值;第二个是可以将 value 值在参数中返回;第三个直接将 value 值写入到传入的 var 对象中。

    3. 加入一对键值对
    4. 修改指定 key 值的 value 值
    作者直接使用了一个函数即完成了第 3 点和第 4 点的工作:

    template<class T>
    void Config::Add(const std::string& in_key, const T& value)
    {
        // Add a key with given value  
        std::string v = T_as_string(value);
        std::string key = in_key;
        Trim(key);
        Trim(v);
        m_Contents[key] = v;
        return;
    }

    这里使用了 C++ 的 std::map 的特性,如果 key 值在 std::map 中存在,则更新 value 值,否则就新增一对键值对。需要注意的是,这里调用了这行代码:

    std::string v = T_as_string(value);

    其中 T_as_string 函数将用户传入的自定义模板类转化为 std::string 类型进行存储,而该方法的实现如下:

    /* static */
    template<class T>
    std::string Config::T_as_string(const T& t)
    {
        // Convert from a T to a string  
        // Type T must support << operator  
        std::ostringstream ost;
        ost << t;
        return ost.str();
    }

    这个类直接调用了用户自定义模板类的 operator<< 重载操作符函数,也就是说,只要用户自定义数据结构自定义重载了 operator<< 操作符函数,就可以用 Config 类来进行 value 值的读写操作了。

    5. 删除一对键值对

    void Config::Remove(const string& key)
    {
        // Remove key and its value  
        m_Contents.erase(m_Contents.find(key));
        return;
    }

    幸而有 C++ STL 强大的功能,删除一对键值对就是这么简单。

    6. 另外的一些方法
    作者为了方便用户使用,还提供了诸如查询文件是否存在、键值是否存在、读入文件、设置获取键值分隔符、设置获取注释标识符等等方法。都是比较简单并且易用的,感兴趣的同学可以自行查看源码。

    四、Config 的使用 Demo

    这里,我自行编写了一个 Demo 来测试 Config 类的功能:

    #include <iostream>
    #include <cstdlib>
    #include <string>
    #include <fstream>
    #include "Config.h"
    
    int main()
    {
        // 打开一个写文件流指向 config.ini 文件
        std::string strConfigFileName("config.ini");
        std::ofstream out(strConfigFileName);
        // 初始化写入注释
        out << "# test for config read and write\n";
        // 写入一对配置记录: name = wangying
        out << "name = wangying\n";
        out.close();
    
        // 初始化 Config 类
        Config config(strConfigFileName);
    
        // 读取键值
        std::string strKey = "name";
        std::string strValue;
        strValue = config.Read<std::string>(strKey);
        std::cout << "Read Key " << strKey << "'s Value is " 
             << strValue << std::endl;
    
        // 写入新键值对
        std::string strNewKey = "age";
        std::string strNewValue = "23";
        config.Add<std::string>(strNewKey, strNewValue);
    
        // 将 Config 类的修改写入文件
        out.open(strConfigFileName, std::ios::app);
        if (out.is_open()) {
            // 利用 Config 类的 << 重载运算符
            out << config;
            std::cout << "Write config content success!" << std::endl;
        }
        out.close();
    
        system("pause");
        return 0;
    }

    幸而有强大的 Config 类,让我操作配置文件变成了一件这么简单的事情!

    output

    config generate

    然而这里需要注意的是,我们在使用 Config 类进行了 Add() 操作之后,我们仅仅只是在 Config 类中操作了 std::map 类型的 m_Contens 对象内容而已,我们还需要将其写入到文件中去,因此这里我最后调用了写文件流进行写入操作,注意这行代码:

    // 利用 Config 类的 << 重载运算符
    out << config;

    这里隐含调用了 Config 类的 operator<< 重载运算符:

    std::ostream& operator<<(std::ostream& os, const Config& cf)
    {
        // Save a Config to os  
        for (Config::mapci p = cf.m_Contents.begin();
            p != cf.m_Contents.end();
            ++p)
        {
            os << p->first << " " << cf.m_Delimiter << " ";
            os << p->second << std::endl;
        }
        return os;
    }

    哈哈哈,看吧,就这么简单!

    至此,完结撒花 ^_^

    五、总结

    这是一个非常非常强大而又异常短小的配置文件读写类,细细品之反而又觉得意味无穷。

    回想我们引言里说到的三点:

    1. 支持读入一个指定配置文件的能力

    2. 支持随时加入一个配置项的能力

    3. 足够强大,能够写入各种数据结构的配置信息

    Config 类无一不一一满足甚至提供了更加人性化的方法供用户使用。

    阅读他人的代码并且了解其设计思路本身就是一个很快乐的事情:)

    To be Stronger!

    展开全文
  • .config生成

    2016-03-26 10:02:20
    (1)命令执行追溯 Sourcebuild/envsetup....执行envsetup.sh脚本,把(TARGET_DEVICE)/BoardConfig.mk包含了进来 build/envsetup.sh:628: localTOPFILE=build/core/envsetup.mk -->build/core/envsetup.mk:161: $(sh

    (1)命令执行追溯

    Sourcebuild/envsetup.sh

     

    执行envsetup.sh脚本,把(TARGET_DEVICE)/BoardConfig.mk包含了进来

    build/envsetup.sh:628:    localTOPFILE=build/core/envsetup.mk

    -->build/core/envsetup.mk:161:          $(shell test -d device && find device -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \

     

    下面为里面的内容

    CPXXX/AndroidBoard.mk:34:includekernel/AndroidKernel.mk

     

    device/yulong/CPXXX/AndroidBoard.mk

     

     21 ifeq ($(KERNEL_DEFCONFIG),)

     22    ifeq ($(TARGET_BUILD_VARIANT),user)

     23      KERNEL_DEFCONFIG := msm-perf_defconfig

     24    else

     25      KERNEL_DEFCONFIG:= msm_defconfig

     26    endif

     27 endif

     

    (2)进入Kernel/AndroidKernel.mk

     24 KERNEL_HEADER_DEFCONFIG := $(strip$(KERNEL_HEADER_DEFCONFIG))

     25 ifeq ($(KERNEL_HEADER_DEFCONFIG),)

     26 KERNEL_HEADER_DEFCONFIG:= $(KERNEL_DEFCONFIG)

     27 endif

     

      50 KERNEL_OUT :=$(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ

     51 KERNEL_CONFIG :=$(KERNEL_OUT)/.config              //----------------------------目标文件

     

     99 $(KERNEL_CONFIG): $(KERNEL_OUT)

    100         $(MAKE) -C kernel O=../$(KERNEL_OUT)ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG)

    101         $(hide) if [ ! -z"$(KERNEL_CONFIG_OVERRIDE)" ]; then \

    102                         echo "Overridingkernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \

    103                         echo$(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \

    104                         $(MAKE) -C kernelO=../$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE)oldconfig; fi

     

    (3)kernel/scripts/kconfig/Makefile

    106 %_defconfig:$(obj)/conf

    107         $(Q)bash$(srctree)/scripts/kconfig/yl_config.sh $@

    108         $(Q)$<--defconfig=arch/$(SRCARCH)/configs/.$@ $(Kconfig)

     

    由上面可知需要依赖scripts/kconfig/conf

     

    (4)scripts/kconfig/conf工具生成如下:

    156 conf-objs       := conf.o  zconf.tab.o

    157 mconf-objs     := mconf.o zconf.tab.o $(lxdialog)

    158 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o

    159kxgettext-objs  := kxgettext.ozconf.tab.o

    160qconf-cxxobjs   := qconf.o

    161 qconf-objs      := zconf.tab.o

    162 gconf-objs      := gconf.o zconf.tab.o

    163

    164 hostprogs-y := conf

     

    5)进入kernel/makefile

     793 export KBUILD_ALLDIRS := $(sort$(filter-out arch/%,$(vmlinux-alldirs)) arch Documentation include samples scripts tools virt)

    进入kernel/scripts/makefile.build

    114 ifneq($(hostprogs-y)$(hostprogs-m),)

    115 include scripts/Makefile.host

    116 endif

     

    (6)进入scripts/Makefile.host

    33 __hostprogs :=$(sort $(hostprogs-y) $(hostprogs-m))

    //---------------为conf

    45 host-cobjs      := $(sort $(foreachm,$(__hostprogs),$($(m)-objs)))

    //----------------conf.o zconf.tab.o

     

    125quiet_cmd_host-cmulti   = HOSTLD  $@

    126       cmd_host-cmulti   = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \

    127                           $(addprefix$(obj)/,$($(@F)-objs)) \

    128                           $(HOST_LOADLIBES)$(HOSTLOADLIBES_$(@F))

    129 $(host-cmulti):$(obj)/%: $(host-cobjs)$(host-cshlib) FORCE

    130         $(call if_changed,host-cmulti)

     

    (7)回到kernel/scripts/kconfig/Makefile

    $(Q)$<--defconfig=arch/$(SRCARCH)/configs/.$@ $(Kconfig)

          scripts/kconfig/conf --defconfig=arch/arm64/configs/.msm_defconfig Kconfig

     

    需要了解多有的kconfig如何合在一起

    展开全文
  • SpringCloud学习系列之四-----配置中心(Config)使用详解

    万次阅读 多人点赞 2019-03-17 22:05:03
    本篇主要介绍的是SpringCloud中的分布式配置中心(SpringCloud Config)的相关使用教程。 SpringCloud Config Config 介绍 Spring Cloud Config项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个...
  • 查看Linux内核配置文件(.config

    万次阅读 2018-11-01 08:41:02
    .config是内核配置文件,在不同场景下获得方法不一样 1 源代码 在kernel文件夹下,按快捷键【Ctrl + H 】显示隐藏文件,即可找到.config文件 2 当前Linux系统 当前的Linux内核的配置文件保存到了/proc/config....
  • App.Config 学习笔记

    千次阅读 2019-03-06 22:58:23
    基础概念 App.config简介 App.config的用处 App.config相关资源 App.Config配置 App.Config读取 App.Config更新
  • 什么是JavaConfig

    千次阅读 2018-09-11 22:18:39
    java config是指基于java配置的spring。传统的Spring一般都是基本xml配置的,后来spring3.0新增了许多java config的注解,特别是spring boot,基本都是清一色的java config。 @Configuration  在类上打上这一标签...
  • config_load的属性

    千次阅读 2012-11-08 21:22:37
    属性 类型 是否必须 缺省值 描述 file string Yes n/a 待包含的配置文件的名称 section string No n/a 配置文件中待加载部分的...加载数据的作用域,取值必须为local, parent 或 global....
  • <template> <view> <view class="search-input-box"> <view class="search-scroll" :class="{aniamtedTop}">...view class="search-list" v-for="(item,index) in searchList">...
  • spring cloud config server配置要点教程 @EnableDiscoveryClient @EnableConfigServer Could not locate configserver via discovery java.lang.IllegalStateException: No instances found of configserver解决
  • 修改git config配置文件

    万次阅读 2018-07-20 11:09:31
    比如:你发现用你的git...1.git config --global --add configName configValue 解释:给指定的级别的指定config增加一个值 示例: 2.删 git config --global --unset configName (只针对存在唯一值的情况) 为...
  • 权限不够 https://www.crifan.com/mac_brew_update_error_could_not_lock_config_file_git_config_permission_denied/
  • 今天设置git用户和密码时突然报错error:could not lock config file .../.gitconfig:No such file or directory检查了C:/Users/LC目录下是有.gitconfig配置文件的,在网上搜查的方法都不适用,花了很常时间才发现...
  • Step By Step制作软盘上的Linux(V0.04)

    万次阅读 2007-08-27 20:16:00
    Step By Step制作软盘上的Linux(V0.04)By : 吴垠Email : lazy_fox#msn.comDate : 2006.02.16Link : http://blog.csdn.net/wooin/archive/2006/01/16/580922.aspx写在前面: 本文的目的是为了不管一切理论和不择...
  • 解决Android平台移植ffmpeg的一揽子问题

    万次阅读 热门讨论 2011-05-30 21:51:00
    IT行业是一个踩在巨人肩膀上前进的行业,否则做的事情不一定有意义,所以我也是基于havlenapetr移植的ffmpeg基础上做了些改进,他做的主要贡献有:1. 移植了ffmpeg并将与媒体相关的结构体在java层重新进行了封装,...
  • $ git config --global user.name "yourname" 2.设置用户邮箱 $ git config --global user.email myemail@qq.com 3.查看git设置列表信息 $ git config --list 4.查看用户名 $ git config user.name
  • 微信开发 遇到 config:invalid url domain

    万次阅读 2016-09-25 14:21:24
    微信开发中遇到 config:invalid url domain的原因 此错误原因 是微信公众号后台配置的微信安全网址 跟当前页面的域名不一致导致
  • git config --global user.email “你的邮箱” 查看配置 git config --list 修改你的用户名和邮箱 git config --global --replace-all user.name “你的用户名” git config --global --replac...
  • arm64-v8a编译

    万次阅读 2016-08-25 16:04:45
    环境:Ubuntu64和android-ndk-r11c(其他不支持arm64-v8a架构) 重点:依赖库要使用android-ndk-r11c编译成arm64-v8a。其中ffmpeg最复杂,编译方法如下: 1、ffmpeg编译 目录建立: ...jni/ffmpeg
1 2 3 4 5 ... 20
收藏数 2,067,873
精华内容 827,149
关键字:

config