前言
Spring Boot 2正式发布已经有段时间,应用升级之前,starter先要升级,那么如何支持Spring Boot 2?
starter同时兼容spring-boot-1和spring-boot-2">为什么选择starter同时兼容spring boot 1和spring boot 2
从用户角度来看
如果不在一个starter里兼容,比如用版本号来区分,spring boot 1的用户使用1.*
,spring boot 2用户使用2.*
,这样用户升级会有很大困扰。
另外,我们的starter是以日期为版本号的,如果再分化,则就会出现2018-06-stable-boot1
,2018-06-stable-boot2
,这样子很丑陋。
从开发者角度来看
要同时维护两个分支,劳务派遣管理系统,修改代码时要合到两个分支上,发版本时要同时两个。如果有统一的bom文件,也需要维护两份。工作量翻倍,昆山软件开发,而且很容易出错。
因此,我们决定在同一个代码分支里,同时支持spring boot 1/2。减少开发维护成本,减少用户使用困扰。
编写兼容的starter的难点
spring boot starter的代码入口都是在各种@Configuration
类里,这为我们编写兼容starter提供了条件。
但还是有一些难点:
通过ASM分析现有的starter里不兼容的类
springboot-classchecker可以从jar包里扫描出哪些类在spring boot 2里不存在的。
工作原理:springboot-classchecker自身在pom.xml里依赖的是spring boot 2,扫描jar包里通过ASM分析到所有的String,提取出类名之后,再尝试在ClassLoader里加载,如果加载不到,则说明这个类在spring boot 2里不存在。
例如扫描demo-springboot1-starter.jar
:
mvn clean package java -jar target/classchecker-0.0.1-SNAPSHOT.jar demo-springboot1-starter.jar
结果是:
path: demo-springboot1-starter.jar org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration
那么这些类在spring boot 2在哪里了?
实际上是改了package:
org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration
通过扫描20多个starter jar包,昆山软件开发,发现不兼容的类有:
可以总结:
spring-boot-utils兼容工具类
spring-boot-utils提供兼容工具类,同时支持spring boot 1/2。
BinderUtils
在spring boot 1里,注入环境变量有时需要用到RelaxedDataBinder
:
MyProperties myProperties = new MyProperties(); MutablePropertySources propertySources = environment.getPropertySources(); new RelaxedDataBinder(myProperties, "spring.my").bind(new PropertySourcesPropertyValues(propertySources));
在spring boot 2里,RelaxedDataBinder
删除掉了,新的写法是用Binder
:
Binder binder = Binder.get(environment); MyProperties myProperties = binder.bind("spring.my", MyProperties.class).get();
通过BinderUtils,则可以同时支持spring boot1/2:
MyProperties myProperties = BinderUtils.bind(environment, "spring.my", MyProperties.class);
@ConditionalOnSpringBoot1/@ConditionalOnSpringBoot2
spring boot starter的功能大部分都是通过@Configuration
组装起来的。spring boot 1的Configuration类,不能在spring boot 2里启用。则可以通过@ConditionalOnSpringBoot1
,@ConditionalOnSpringBoot2
这两个注解来分别支持。