Springboot是目前开源项目中很常用的框架技术,今天就来聊一下Springboot中多环境配置是如何实现的。即application.yml中spring.profiles.active配置不同环境,系统是如何自动加载识别加载的。
我们以Springboot的启动类的主程序来讲解application的加载逻辑。
在主程序方法中,打印容器中获取到User对象,它只有一个name属性。
这里name属性引用了外部配置user.username的值,它是从配置文件中读取,这里我定义两个配置文件设置该属性,application.properties和application-prod.properties。
有了配置文件之后,启动SimapleSpringApplication程序,我们首先可以看到日志输入:UserBean:User(name=one),由此可以看出程序读取了application.properties的user.username配置。现在我们在application.properties中加入一行:
再次重启启动程序,可以看到控制台如下日志:
此时User对象的name属性变成了application-prod.properties中定义的值,并且日志提示Thefollowingprofilesareactive:prod表明了名称为prod的Profile在程序中激活。接下来我们就从这个日志入手,探究下这一切是如何发生的。
首先,根据IDE的全局查找功能,个人习惯可以设置快捷键,比如我的是同时按住Crtl+Shift+R之后搜索Thefollowingprofilesareactive:这些词出现的位置,进行定位,可以找到这个日志出现于SpringApplication#logStartupProfileInfo方法之中。
从log.info日志中分析,我们可以看出打印的activeProfiles来自上下文的environment对象,然后向上追踪查看logStartupProfileInfo的调用位置,可以在SpringApplication#prepareContext方法之中找到,这个方法从命名上就可以看出是主要负责SpringBoot运行前容器上下文的预备工作,
我们重新运行程序,通过断点方式拦截SpringApplication#prepareContext方法的指向,获取environment对象真实的类型为StandardEnvironment,是Environment接口非Web环境的标准实现,存储着一些应用配置和Profiles信息,如果在Web环境下,context关联的就是StandardServletEnvironment类型的对象。
知道了日志打印来自StandardEnvironment对象的activeProfiles属性之后,就需要来看它是在什么时间被赋值的了。继续从调用链的上一级查找,我们看到SpringApplication#run(java.lang.String...),这也是整个程序启动的主要方法。
从图中程序我们可以看出第一次得到的environment对象来自SpringApplication#prepareEnvironment内部生成,prepareEnvironment方法内部首先通过getOrCreateEnvironment获取一个基础的ConfigurableEnvironment实例,然后对该实例对象初始化配置返回。
正在创建environment对象来自SpringApplication#getOrCreateEnvironment,看它的实现就可以验证我们之前提到environment对象类型为StandardEnvironment。
了解完environment的创建之后,接下来就