SpringBoot 是原生支持配置迁移的,但是官方文档没有看到这方面描述,在源码中才看到此模块,spring-boot-properties-migrator,幸亏我没有跳过。看到这篇文章的各位,可算是捡到宝了,相信你继续往下看下去,定会忍不住点赞、收藏、关注。 效果 先放个效果吸引你 😃 从 SpringBoot 2.0.0 版本开始,配置服务上下文,不支持 server.context-path,而需要server.servlet.context-path配置。但是只要加上以下一个官方依赖,就可以支持使用 server.context-path org.springframework.boot spring-boot-properties-migrator server.context-path 所对应的属性 ServerProperties#contextPath 在 Java 代码中已不存在,server.servlet.context-path 所对应的的属性在内部类 Servlet 中才有,为何加了此依赖就能实现如此神奇的效果呢。 原理 SpringBoot 对外部化配置原生支持迁移功能,所谓迁移,具体是指对应配置的属性名变动,仍可以使用原来的属性名配置。 在 spring-configuration-metadata.json 的信息可以辅助 IDE 进行配置的提示,也可以用来完成配置的迁移。非常的简单。 相关文章: SpringBoot 配置提示功能 通过阅读代码,获得以下信息: 监听 ApplicationPreparedEvent 事件(即:环境已准备事件),执行以下操作并收集信息 从 classpath*:/META-INF/spring-configuration-metadata.json 中载入所有配置 从上下文的 environment 中过滤出提示的配置(满足条件:1. deprecation 不为 null,且提示 level 为 error) 判断是否兼容(兼容条件见下一节),提取出兼容的属性 将 value 对应到 replacement 的 key,并将其属性源命名为:migrate-原名 将配置迁移的新属性源添加到 environment 中,且添加到原属性源之前(优先级高)。 监听事件:ApplicationReadyEvent(应用上下文已准备) 或 ApplicationFailedEvent(应用启动失败),打印以上步骤收集的遗留配置信息。以 warn 级别打印兼容的配置,以 error 级别打印不兼容的配置 配置兼容条件 根据元数据中定义的 type 判断 如果旧类型、新类型其中之一为 null(元数据中未指定),则不兼容 如果两个类型一样,兼容 如果新类型是 Duration,而旧类型是 Long 或 Integer,则兼容 其他情况视为不兼容 从 environment 中取配置信息,理论上支持 SpringBoot 所有的配置方式。 效果 兼容效果: 弃用属性(如果还存在)与替换后的属性都会使用配置文件中的弃用的属性名所对应的的值。 总结 使用配置迁移功能,需要以下步骤: 引入依赖:spring-boot-properties-migrator(支持配置迁移)、spring-boot-configuration-processor(生成元数据文件,如果已经有完整的,不需要此依赖) 元数据文件spring-configuration-metadata.json 中弃用属性名对应的 properties 中必须有 deprecation(在additional-spring-configuration-metadata.json 中添加,相关文章: SpringBoot 配置提示功能 ) deprecation 中需指定 level 为 error deprecation 中需指定 replacement replacement 对应的属性配置在元数据文件中存在,与弃用属性兼容 经典示例之配置上下文 再说回一开始展示的配置上下文示例。 # 配置 servlet 服务上下文 server: context-path: test 从 SpringBoot 2.0.0 版本开始,以上配置不支持,点到配置元数据文件中(spring-configuration-metadata.json),发现如下信息: { "properties": [ { "name": "server.context-path", "type": "java.lang.String", "description": "Context path of the application.", "deprecated": true, "deprecation": { "level": "error", "replacement": "server.servlet.context-path" } }, { "name": "server.servlet.context-path", "type": "java.lang.String", "description": "Context path of the application.", "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties$Servlet" } 替换属性名为:server.servlet.context-path,此属性在org.springframework.boot.autoconfigure.web.ServerProperties 中,且在类中可以发现,server.context-path 所对应的属性 ServerProperties#contextPath 在代码中已不存在,而是在内部类 Servlet 中有,也就是对应 server.servlet.context-path 的属性才有。 但是其满足配置兼容的条件,为什么实际上使用却好像不兼容呢? 其实是因为没有引入依赖,当引入依赖,就会发现此方式配置可以起作用。 示例之两种属性都存在 代码示例见 https://gitee.com/lw888/spring-boot-source-example/tree/master/properties-migrator 1、引入依赖 org.springframework.boot spring-boot-properties-migrator org.springframework.boot spring-boot-configuration-processor true 2、Java 配置 此处故意保留弃用属性 @Data @Configuration @ConfigurationProperties(prefix = "my") public class MyProperties { /** the project name */ private String name; private App app; @Data public static class App { private String name; } } 3、元数据配置,spring-configuration-metadata.json 由程序生成,自定义配置放在 additional-spring-configuration-metadata.json 中 { "properties": [ { "name": "my.name", "type": "java.lang.String", "description": "the project name.", "deprecation": { "reason": "test the properties-migrator feature.", "replacement": "my.app.name", "level": "error" } }, { "name": "my.app.name", "type": "java.lang.String", "sourceType": "com.lw.properties.migrator.config.MyProperties$App", "description": "the project name." } ] } 4、在 properties 或 yml 文件中配置 my: name: lw app: name: app 5、打印配置信息 @Slf4j @SpringBootApplication public class PropertiesMigratorApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(PropertiesMigratorApplication.class, args); MyProperties myProperties = context.getBean(MyProperties.class); log.info("myProperties.name:{}", myProperties.getName()); log.info( "myProperties$app.name:{}", Optional.ofNullable(myProperties.getApp()).orElse(new App()).getName()); } } 6、打印信息如下: 2019-11-23 21:42:09.580 WARN 109408 --- [ main] o.s.b.c.p.m.PropertiesMigrationListener : The use of configuration keys that have been renamed was found in the environment: Property source 'applicationConfig: [classpath:/application.yml]': Key: my.name Line: 4 Replacement: my.app.name Key: server.context-path Line: 2 Replacement: server.servlet.context-path Each configuration key has been temporarily mapped to its replacement for your convenience. To silence this warning, please update your configuration to use the new keys. ......... myProperties.name:lw ......... myPropertiesapp.name:lw.........serverPropertiesservlet.contextPath:/app 7、效果解析 在 yml 中弃用属性名优先级更高,弃用属性与新属性都使用此弃用属性名对应的值。 参考资料 SpringBoot 2.2.1.RELEASE 源码 公众号:逸飞兮(专注于 Java 领域知识的深入学习,从源码到原理,系统有序的学习)https://www.cnblogs.com/lw5946/p/11933190.html