个人微信号:geekoftaste, 期待与大家一起探讨!

背景

我们知道 SpringBoot 有一个全局的配置文件 application.properties, 可以把工程里用到的占位符,第三方库的配置项如 dubbo 端口,工程的 db 配置等统一放在这个配置文件里,方便对工程里所有配置项的统一管理。我们知道,在企业开发中,我们一般会先在测试环境中开发,在预发环境环境,最后上生产环境部署,也就意味着一个工程需要分别部署在测试,预发,生产环境上,而这三种环境的一些配置项(如测试环境和生产环境的 db 配置)很多时候都是不一样的,所以我们通常需要为每一个环境准备一份 application.properties, 接下来就引申出一个问题

如何维护多环境下的 application.properties 文件

方法一:在工程里维护多个环境的 application.properties ,部署的时候通过  spring.profiles.active 来指定工程应用哪个环境的 application.properties 文件,比如预发配置文件我们用 application-pre.properties, 线上配置文件我们用 application-prod.properties,当想在预发部署工程时,我们在部署脚本里用 java -jar xxxxx.jar --spring.profiles.active=pre 这样的方式来指定工程启动使用预发的 application-pre.properties 配置文件

以上这种方式虽然可以满足要求,但有一个比较棘手的问题:在部署脚本里需要先根据 ip 等来判定当前环境是预发还是线上

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

如上所示,部署脚本需要根据一个标志来判断是预发还是线上,以便指定相应的 spring.profiles.active,这个标志的维护就是一个成本 ,每个环境的部署机器都要能正确设置这个 flag 的值,维护的成本很大

方法二:也就是我们工程当前采用的方式除了用 spring.profiles.active 来指定到底用工程中哪种环境的 application.properties,我们还可以用

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

这种指定配置文件位置的方式来使用指定的 application.properties 文件

使用这种方式就解决了方法一的问题,只要在工程里维护多个环境下的 application.properties 文件(如下)

当  gradle build 通过之后,在每个环境的机器部署前都会把工程里相应环境对应的 application.properties 统一 copy 到机器的固定目录下,如 /opt/conf下, 然后在启动的时候,通过在启动命令里指定 spring.config.location=/opt/conf/application.properties 的方式来指定 jar 包使用此环境下的 application.properties 文件即可

问题初现:多环境下的 application.properties 如何维护

在上图我们可以看到,由于我们有多个预发及线上环境,不得不为这些环境分别指定一个 application.properties,这样导致的后果就是如果我需要在一个 application.properties 文件里添加一个配置,不得不在其他环境下的 application.properties 文件里也 手动 添加此配置,这样的工作不仅烦琐,而且很容易出错, 之前就有发生过同事只在预发的 application.properties 加配置而忘记在线上加导致的线上部署失败的问题

如何解决

实际上预发和线上的配置大部分都是一样的,只有少部分是不一样的,所以我们想是否能将大部分一样的配置都统一放到一个文件(姑且叫 application-common.properties)里维护,这样如果要配置一个属性,只需要统一在这一个文件里配置即可,极大地降低了维护成本

那如何解决不同环境下某些配置不同的问题呢,比如在预发和线上我们对 MQ 的 topic 的命名有一个统一的规范,预发我们统一叫 topic-pre-xxx, 线上我们统一叫 topic-prod-xxx。

针对这种不同环境下配置不同的问题,我们可以单独为预发和线上建一个文件,比如预发叫 application-pre.properties, 线上叫 application-prod.properties,把各个环境独有的配置都分别放在这两个文件里即可

好了,现在我们有了三个文件,公用配置文件:application-common.properties, 以及两个环境配置文件:application-pre.properties, application-prod.properties,那怎么生成如下最终各个环境的 application.properties 文件呢

很明显应该把公用配置文件与各个环境的配置文件合并

合并工作的思路很简单,我们以生成预发环境的 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)

这样在 build 构建完之后就会自动执行合并文件的工作了。最后我们来看看最终的合并生成各个环境 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.textdef 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 的噩梦了

application terminated怎么解决_优雅解决 SpringBoot 工程中多环境下 application.properties 的维护问题...相关推荐

  1. python中import requests是什么意思_Ubuntu中python环境下import requests错误的解决(学习过程问题记录)...

    python中导入模块:import requests提示错误,错误信息描述如下:>>>import requests Traceback (most recent last): F ...

  2. springboot工程中maven插件浅析

    springboot工程中都会配置插件进行编译.打包等操作,下面对常用的maven插件进行简单分析. 一.spring-boot-maven-plugin spring-boot-maven-plug ...

  3. java 定时任务怎么关闭_浅谈springboot项目中定时任务如何优雅退出

    在一个springboot项目中需要跑定时任务处理批数据时,突然有个Kill命令或者一个Ctrl+C的命令,此时我们需要当批数据处理完毕后才允许定时任务关闭,也就是当定时任务结束时才允许Kill命令生 ...

  4. python 程序停止打印日志_优雅停止 SpringBoot 服务,拒绝 kill -9 暴力停止!

    在使用 SpringBoot 的时候,都要涉及到服务的停止和启动,当我们停止服务的时候,很多时候大家都是kill -9 直接把程序进程杀掉,这样程序不会执行优雅的关闭.而且一些没有执行完的程序就会直接 ...

  5. 笔记本显示网络电缆被拔出怎么解决_如何解决系统显示网络电缆被拔出的问题...

    日常使用电脑的同时又些朋友可能会遇到正上网或者刚开启电脑的时候提示网络电缆被拔出,这样的现象使人非常厌恶,一般出现这样的现象不是电脑网络连不上就是网络老是中断,使用户无法进行正常网络应用,那么如何解决 ...

  6. yii2 跨域请求配置_如何在SpringBoot应用中实现跨域访问资源和消息通信?

    允许跨域访问 CORS ( Cross Origin Resource Sharing,跨域资源共享)机制允许Web应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行.浏览器支持在API容器中 ...

  7. 机器学习经典算法实践_服务机器学习算法的系统设计-不同环境下管道的最佳实践

    机器学习经典算法实践 "Eureka"! While working on a persistently difficult-to-solve problem, you disco ...

  8. linux nginx 安装_艾编程基础教程:Linux 环境下 Nginx 安装

    #安装说明:Nginx 安装前需要提前安装相关命令和工具包: make 命令.gcc g++.pcre.zlib.openssl 1.安装 gcc g++ #ubuntu 环境下安装 apt-get ...

  9. div固定大小文字溢出自动缩小_【高并发】高并发环境下如何防止Tomcat内存溢出?看完我懂了!!

    写在前面 随着系统并发量越来越高,Tomcat所占用的内存就会越来越大,如果对Tomcat的内存管理不当,则可能会引发Tomcat内存溢出的问题,那么,如何防止Tomcat内存溢出呢?我们今天就来一起 ...

最新文章

  1. 中国电子学会青少年编程能力等级测试图形化四级编程题:随机选T恤
  2. mysql报错无效默认值1067_Mysql 报错:#1067 - Invalid default value for 'update_time
  3. iphone保修期多久_卖疯了!开发区9.9元起换iphone原厂电池!
  4. python柱形图代码_Python数据可视化:基于matplotlib绘制「条形图」
  5. 斯坦福大学NLP公开课CS224n上映啦!华人助教陪你追剧
  6. 【C#桌面应用】第一节:使用C#开发桌面应用的准备
  7. 软件行业正面临一场新的变革——SaaS软件
  8. 小学生python编程教程-极度舒适的全套 Python 入门教程,小学生看了也能学会
  9. java面试 bs cs_面试题思考:BS与CS的区别与联系
  10. linux系统pyodbc安装与使用教程
  11. Excel基础教程(2)——函数与公式
  12. Chuck语言学习笔记——1.环境搭建与程序运行
  13. Android实现播放音乐列表
  14. bigworld源码分析(3)——dbMgr分析
  15. javascript_JSON.parse() 与 JSON.stringify()_ZHOU125disorder_
  16. 从零开始,创建一个VUE项目,详细图文详解。
  17. android 4.0 原生短信,Android 4.0 短信发不出去解决办法
  18. 分辨率,像素,dp之间的联系
  19. windoes 平台 Qt 的下载与安装-(Qt 5.15.2 LTS,这是一个长期支持版本)
  20. 不知道怎样做自媒体视频剪辑?分享几个必备素材网站

热门文章

  1. 《jQuery Cookbook中文版》——1.9 根据当前上下文遍历DOM获得新的DOM元素集
  2. WP开发笔记——页面传参
  3. SBT管理java项目
  4. rpm apache2 啟動vhost .htaccess讀取問題
  5. 让C++代码与C#代码一起生成一个单一的Assembly
  6. 设计Whats App
  7. 6-2 函数式编程例一
  8. python电脑怎么打开任务管理器_利用Python调用Windows API,实现任务管理器功能
  9. 基于php计算机等级考试系统毕业设计网站作品
  10. 个人计算机多核cpu好处,CPU是多核好还是高主频好?