前言

基于现代服务的云原生十二要素理论,我们在采用容器化部署时,要保证同一个镜像可以满足不同环境的部署要求,而不是不同环境打包不同的镜像。本文档主要介绍一种基于spring框架的满足不同环境配置的编译打包方案,满足同一个镜像可以在环境分组下通过启动项配置实现不同环境的部署。

现有方案及问题

我们见过最常见的配置文件管理方案,是基于Maven的profile配置来实现多环境切换的,它的弊端在于,我们将profile配置在pom.xml中,每次编译打包时,需要通过编译指令-P来标识当前环境配置。这样导致的问题是,我们打包的镜像具有了环境属性,不符合一个镜像多环境部署的要求。

还有一种配置方案,就是基于Spring profile进行配置文件管理。针对这两种方案,我接下来会进行一些分析和对比。

两种profiles配置的不同和优劣对比

a. 两种profiles方案对比

  1. Maven 的 profiles:

◦ Maven 的 profiles 是在构建时根据环境或其他条件激活不同的配置集合。可以在项目的pom.xml文件中定义多个 profile,并使用 Maven 命令行参数或其他配置来激活特定的 profile。

◦ 优势:

灵活性高,可以根据不同的构建环境或条件激活不同的 profile。

可以在构建过程中使用不同的依赖、插件配置等。

◦ 劣势:

配置相对分散,需要在 Maven 的pom.xml文件中定义和管理多个 profile。

配置与代码分离,不够直观。

  1. Spring 的application.properties的 profile 配置:

◦ Spring 的application.properties文件可以根据激活的 profile 来加载不同的配置。可以在application.properties文件中定义多个 profile 下的配置,并使用配置文件或环境变量来激活特定的 profile。

◦ 优势:

配置集中,可以在一个文件中定义多个 profile 下的配置,更易于管理和维护。

配置与代码相近,更直观易读。

◦ 劣势:

激活 profile 的方式相对有限,通常需要通过配置文件或环境变量来指定。

不适用于构建过程中的配置,主要用于应用程序的运行配置。

总的来说,Maven profiles 更适用于构建过程中的配置,可以根据构建环境或条件激活不同的 profile,而 Spring 的application.properties的 profile 配置更适用于应用程序的运行配置,可以根据不同的 profile 加载不同的配置。具体选择哪种方式取决于你的需求和偏好。

b. 在云原生和容器化的部署场景分析

在云原生和容器化的部署场景下,我更倾向使用 Spring 的application.properties的 profile 配置方式。

以下是在云原生和容器化部署场景下,使用application.properties的 profile 配置方式的优势:

  1. 环境无关性:application.properties可以根据激活的 profile 加载不同的配置,使得应用程序在不同的环境中运行时具有一致的行为。这对于云原生和容器化的部署非常重要,因为应用程序可能需要在不同的环境(例如开发、测试、生产)中运行。
  2. 配置集中化:使用application.properties的 profile 配置方式,可以在一个文件中定义多个 profile 下的配置,使得配置管理更加集中和方便。这对于云原生和容器化的部署场景非常有帮助,因为可以根据不同的 profile 加载适当的配置,而无需分散地管理多个 Maven profiles。
  3. 容器友好性:在容器化的部署场景中,通常使用容器编排工具(如 Kubernetes)来管理应用程序的配置和部署。使用application.properties的 profile 配置方式,可以通过环境变量或配置文件中的属性来指定激活的 profile,从而实现与容器编排工具的集成。

综上所述,使用 Spring 的 application.properties 的 profile 配置方式更适合云原生和容器化的部署场景,因为它提供了环境无关性、配置集中化和容器友好性的优势。

基于properties的多环境配置方案实践

以下方案以springboot为例,当然springMVC方案也是可以适配,只是需要额外配置一下,介于我们新项目基本都是基于springboot搭建,此处不展开springMVC的实线方案,如有需要,我再额外提供mvc的配置方案。

a. 配置文件树

如上图所示

  • properties文件夹:我们在properties文件夹下,基于不同的环境,简历单独文件夹,比如dev,online, test, uat等,每个文件夹下存放当前环境的配置信息。
  • spring文件夹: 下存放xml配置信息,比如常见的JSF配置(jsf.xml),以及其他需要通过xml配置注入的业务场景。当然基于springboot官网建议,大家尽量用注解代码方式实现bean注入,尽量减少xml的方式。
  • application.properties文件: 该文件里通过核心的配置spring.profiles.active=**来标识当前是哪个profile环境。当然一些其他全局类配置也可以放在此处。需要注意application.properties文件需要配置在行云部署中分组配置里,因为此文件需要基于不同的部署分组进行文件覆盖,以改变spring.profiles.active的值,如下图所示。当然,也可以通过运行时启动指令,进行不同的profile选择。
  • important.properties文件: 该文件为京东行云部署规约,把秘钥等安全性高的文件以加密存储的方式存放在该文件中,并部署到行云部署分组的远程配置里。

具体行云部署里的配置如下:

b. properties文件加载

正常情况下,properties//*.properties下的配置文件是不会自动加载到启动项里的。所以需要通过额外的方式动态加载,具体方法是通过spring框架下的PropertySourcesPlaceholderConfigurer的类属性,结合环境变量,动态批量加载配置文件。(额外说明,如果是springMVC框架,也可以通过xml配置context:property-placeholder属性来实现。**)

具体代码如下:

  1. /**
  2. * 配置文件环境配置
  3. *
  4. * @Author zhaoyongping
  5. * @date 2023/7/10 15:13
  6. * @ClassName EnvPropertiesConfig
  7. * @Descripiton 配置文件环境配置
  8. **/
  9. @Configuration
  10. public class EnvPropertiesConfig {
  11. /**
  12. * 加载属性配置
  13. *
  14. * @param environment 环境属性
  15. * @return PropertySourcesPlaceholderConfigurer
  16. * @author zhaoyongping
  17. * @date 2023/7/10 15:13
  18. * @description 加载属性配置
  19. */
  20. @Bean
  21. public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfig(Environment environment) throws IOException {
  22. PropertySourcesPlaceholderConfigurer config = new PropertySourcesPlaceholderConfigurer();
  23. String[] activeProfiles = environment.getActiveProfiles();
  24. if (activeProfiles.length > 0) {
  25. String resourceUrl = "classpath:properties/"
  26. + environment.getActiveProfiles()[0] + "/*.properties";
  27. config.setLocations(
  28. new PathMatchingResourcePatternResolver().getResources(resourceUrl));
  29. } else {
  30. //兜底策略
  31. config.setLocations(
  32. new PathMatchingResourcePatternResolver()
  33. .getResources("classpath:properties/dev/*.properties"));
  34. }
  35. return config;
  36. }
  37. }

总结

通过以上步骤,我们可以实现编译打包镜像不需要跟环境变量绑定,而只需要在启动运行时基于不同的分组动态配置的applicaiton.properties文件,来实现不同环境的适配。这种可以在运行时变更配置文件的机制,更适合在云原生时代下的容器化部署方案,也利于我们的服务的可移植性。当然,以上只是笔者个人的一个实践经验,并不能代表它是最优实践方案。

作者:京东物流 赵勇萍

来源:京东云开发者社区 自猿其说Tech 转载请注明来源

Spring配置文件的魔法炼金术:如何制造容器化时代的完美配方的更多相关文章

  1. 容器化时代我们应当选择Kubernetes

    前天发的文章<基于Kubernetes 构建.NET Core 的技术体系>,有同学问.NET Core上有Spring Cloud类似的平台吗? .NET Core出现这么久了,这个为云 ...

  2. 【Day03】Spring cloud:源码讲解与容器化初探

    今日内容 原理和源码 容器化过度 一.Naocs 1.介绍 server端 启动入口类(Spring Boot项目,提供8848端口的监听访问) 源码包含InstanceController类(ser ...

  3. 一份.NET 容器化的调查小结

    小编在上个月在微信公众号"dotnet跨平台" 做了一个针对.NET 容器化的调查:https://mp.weixin.qq.com/s/oszbuIORT0G8XLLgMZzkn ...

  4. 监听器如何获取Spring配置文件(加载生成Spring容器)

    Spring容器是生成Bean的工厂,我们在做项目的时候,会用到监听器去获取spring的配置文件,然后从中拿出我们需要的bean出来,比如做网站首页,假设商品的后台业务逻辑都做好了,我们需要创建一个 ...

  5. 你不知道的Spring配置文件

    Spring配置文件是用于指导Spring工厂进行Bean生产.依赖关系注入(装配)及Bean实例分发的"图纸".Java EE程序员必须学会并灵活应用这份"图纸&quo ...

  6. Spring配置文件详解

      转自: http://book.51cto.com/art/201004/193743.htm 此处详细的为我们讲解了spring2.5的实现原理,感觉非常有用 spring配置文件是用于指导Sp ...

  7. spring配置文件详解--真的蛮详细

    spring配置文件详解--真的蛮详细   转自: http://book.51cto.com/art/201004/193743.htm 此处详细的为我们讲解了spring2.5的实现原理,感觉非常 ...

  8. Spring 配置文件详解 (以2.5为例)

    转载自:http://blog.csdn.net/zzjjiandan/article/details/22922847          Spring配置文件是用于指导Spring工厂进行Bean生 ...

  9. Spring配置文件详解:<context:annotation-config/>和<context:component-scan base-package=""/>和<mvc:annotation-driven />

    <context:annotation-config/> 在基于主机方式配置Spring时,Spring配置文件applicationContext.xml,你可能会见<contex ...

  10. Spring 配置文件applicationContext.xml

    Spring配置文件是用于指导Spring工厂进行Bean生产.依赖关系注入(装配)及Bean实例分发的"图纸". Spring配置文件是一个或多个标准的XML文档,applica ...

随机推荐

  1. Redis从入门到放弃(8):哨兵模式

    在前面的文章中介绍了Redis的主从复制,但主从复制存在一定的缺陷.如果Master节点宕机,因为不具备自动恢复功能,需要人工干预,那么在这个干预过程中Redis将不可用. 为了解决这一问题,Redi ...

  2. [etcd]简介与安装

    简介 etcd是一个采用Raft协议实现强一致性的分布式键值数据库,它提供了一种可靠的方式存储需要被分布式系统或机器集群访问的数据. 常见使用场景:服务注册与发现.键值对存储.消息发布和订阅.分布式锁 ...

  3. 从零玩转系列之微信支付实战PC端支付微信取消接口搭建 | 技术创作特训营第一期

    一.前言 从零玩转系列之微信支付实战PC端支付微信取消接口搭建 | 技术创作特训营第一期 halo各位大佬很久没更新了最近在搞微信支付,因商户号审核了我半个月和小程序认证也找了资料并且将商户号和小程序 ...

  4. 解码Transformer:自注意力机制与编解码器机制详述与代码实现

    本文全面探讨了Transformer及其衍生模型,深入分析了自注意力机制.编码器和解码器结构,并列举了其编码实现加深理解,最后列出基于Transformer的各类模型如BERT.GPT等.文章旨在深入 ...

  5. 在原生APP中集成Unity容器

    随着技术的发展,越来越多的APP期望拥有3D,AR的能力.要达到这个目标可以选择使用原生开发,也可以使用Unity成熟的3D开发技术链,通过嵌入的方式将Unity容器嵌入到APP中.这里介绍的是通过嵌 ...

  6. GAN!生成对抗网络GAN全维度介绍与实战

    本文为生成对抗网络GAN的研究者和实践者提供全面.深入和实用的指导.通过本文的理论解释和实际操作指南,读者能够掌握GAN的核心概念,理解其工作原理,学会设计和训练自己的GAN模型,并能够对结果进行有效 ...

  7. 给微软.Net runtime运行时提交的几个Issues

    前言 因为目前从事的CLR+JIT,所以会遇到一些非常底层的问题,比如涉及到微软的公共运行时和即时编译器或者AOT编译器的编译异常等情况,这里分享下自己提的几个Issues. Issues 一.iss ...

  8. 4.go语言复合类型简述

    目录 1. 本章前瞻 2.来自leetcode的例题 描述 分析 题解 3. 复合类型新版本的变化 3.1 string和[]byte的高效转化 3.2 内置函数clear 4. 复合类型概述 4.1 ...

  9. SpringBoot获取树状结构数据-SQL处理

    前言 在开发中,层级数据(树状结构)的获取往往可能是我们一大难点,我现在将自己获取的树状结构数据方法总结如下,希望能给有需要的小伙伴有所帮助! 一.测试数据准备 /* Navicat Premium ...

  10. js合并对象常用方法

    const person = { name: 'David Walsh', gender: 'Male' }; const tools = { computer: 'Mac', editor: 'At ...