Elegant solve maintenance problems SpringBoot engineering application.properties in Multiple Environments

Micro Signal: geekoftaste, look forward to discuss with you!

background

We know SpringBoot have a global profile application.properties, can be used in the project placeholders, configuration items, such as third-party libraries dubbo port, db configuration and other works on this unified configuration file, to facilitate the project unified management in all configuration items. We know that, we will normally develop in a test environment in the enterprise development, environment environment in advance, the final production environment deployment, which means that a project needs to be deployed in each test, advance, on the production environment, Some configuration items these three environments (such as test and production environments db configuration) often are not the same, so we usually need to prepare a application.properties for each environment, then they come out of a problem

How to maintain application.properties files in multi-environment

Method One: When application.properties maintain multiple environments in the project, deployed by spring.profiles.active application.properties file to specify which environmental engineering applications, such as pre-made profiles we use application-pre.properties, line we use the configuration file application-prod.properties, when you want to advance in the deployment project, we are in the script with the deployment of java -jar xxxxx.jar --spring.profiles.active = pre such a way to start using pre-designated projects issued application-pre.properties profile

Although this method can satisfy the above requirements, but there is a more difficult problem:
the need to advance the current environment is still online ip, etc. to determine in accordance with the deployment script

if [ "$flag" == "预发" ]; then
        java -jar xxxxx.jar --spring.profiles.active=pre
else 
        java -jar xxxxx.jar --spring.profiles.active=prod

As described above, according to the deployment of a script needs to judge flag advance or line, in order to specify the spring.profiles.active, this flag is a maintenance cost of each machine deployment environment must be able to correctly set the flag cost value and maintenance of large

Method two: that is the way we project currently employed
except spring.profiles.active be specified in the end with what application.properties engineering environment, we can also use

java -jar xxxxx.jar --spring.config.location=/opt/conf/application.properties

This configuration file specifies the location of the ways to use the specified file application.properties

Using this method a way to solve the problem, as long as the maintenance application.properties files in multiple environments in engineering in (below)

Then when deployed, when gradle build after the adoption, deployment will be in front of each machine environment to environment corresponding application.properties unified copy machine to a fixed directory, such as /opt/confunder, then at startup by the startup command in Specifies spring.config.location = / opt / conf / application.properties way to specify the use of the package application.properties jar file in this environment can be

Early question now: application.properties under multi-environment how to maintain

In the graph we can see that because we have more advance and online environment, these environments have designated as a application.properties respectively, due to the consequences of this is that if I need to add a application.properties in a configuration file had also in application.properties files in other environments manually add this configuration, this job is not only tedious, error-prone, before there had only happened colleagues in advance of application.properties plus configuration plus forget online line failure caused by deployment issues

How to solve

In fact Configuration advance and lines are mostly the same, only a small part is not the same, so if we want to be able to most of the same configuration are unified into a file (let's call application-common.properties) in maintenance, so if you want to configure a property, you only need to configure unified in this one file, which greatly reduces maintenance costs

How to solve some of the different circumstances of different configuration problem then, for example, in advance online and we have a unified specification of the topic name MQ, and advance our unified call topic-pre-xxx, unified line we call topic-prod-xxx.

In this configuration for different environments different problems, we can advance and online to build a separate file, such as pre-made call application-pre.properties, online called application-prod.properties, the unique configuration of each environment are respectively placed in these two documents can be

Well, now we have three files, public profile: application-common.properties, and two environmental profile: application-pre.properties, application-prod.properties ,, how to generate application that follows the final each environment .properties file it

Obviously the public profile combined with the various environmental profile

合并工作的思路很简单,我们以生成预发环境的 application.properties为例,如下

  1. 遍历 application-common.properties 文件中的每一行,然后取出每一行的 key,value(以等号分割),将其存储到 map中

  2. 遍历 application-pre.properties 的每一行,然后取出每一行的 key,value(以等号分割),取出的同时拿 key 到上一步的 map去查找, 如果存在则覆盖,如果不存在则在上一步的 map 中新增 key, value

  3. 遍历步骤 2 最终的 map将每个键值对以 key=value 的形式写入 pre 中的 applicaton.properties 文件

还有一个问题,这个合并工作写在哪里呢,答案是 gradle 的 task 里,我们的工程是基于 gradle 构建的,一般我们是通过 gradle build 来编译打包工程的,我们可以在 gradle build 打包之后再执行这个 task ,假设这个 task 名为 regeneratePropertyFile ,则可写成如下形式

build.finalize(regeneratePropertyFile)

最后我们来看看最终的合并生成各个环境 application.properties 的 task

task regeneratePropertyFile(type:Exec){
 ["pre", "prod"].each { env ->
                def envMap = [:]    
              // 取出公共文件的键值对
        def destFileName = "src/main/resources/META-INF/spring/properties/application-common.properties"
        def destFile = file(destFileName)
        String content = destFile.text
        def commonLines = destFile.readLines()
        for (line in commonLines) {
            Integer equalSignLoc = line.indexOf("=")
            if (equalSignLoc == -1) {
                continue
            }

            String key = line.substring(0, equalSignLoc)
            String value = line.substring(equalSignLoc + 1)
            envMap.put(key, value)
        }

        // 取出环境配置文件 application.properties 的键值对,写入envMap中
        File envFile = file("src/main/resources/META-INF/spring/properties/application-${env}.properties")
        def envLines = envFile.readLines()
        for (line in envLines) {
            Integer equalSignLoc = line.indexOf("=")
            if (equalSignLoc == -1) {
                continue
            }

            String key = line.substring(0, equalSignLoc)
            String value = line.substring(equalSignLoc + 1)
            envMap.put(key, value)
        }

        content = ""
        envMap.each { key, val ->
            content = "${content}\n"
        }
                // 写入最终环境的 application.properties 文件
        destFile = file("${rootProject.projectDir}/bb_conf/${env}/application.properties")
        destFile.text = content       
    }
}

搞定!妈妈再也不用担心我在多环境下维护多个 application.properties 的噩梦了

公众号:「码农蜕变之路」,欢迎关注哦

Guess you like

Origin www.cnblogs.com/xiekun/p/11441380.html