前言
注释开始前,咱们做个小测试,假如咱们封装了一个 springboot starter,其主动拆卸类形如下内容
@Configuration
@EnableConfigurationProperties({ApolloRefreshProperties.class})
public class ApolloRefreshAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass({ConfigService.class})
public ApolloRefreshService apolloRefreshService(ApolloRefreshProperties properties) {return new ApolloRefreshService(properties);
}
}
该 starter 的 pom 引入的 apollo gav 是 optional
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo-client.version}</version>
<optional>true</optional>
</dependency>
我的问题是
在运行环境为 jdk8 的 springboot 我的项目引入上述的 starter,是否会有问题?
咱们运行一下,发现会呈现
而后咱们不改任何一行代码,把 JDK 调成 11 或者以上版本,再运行
我的项目胜利运行。那咱们的修复的第一直觉是不是把 JDK8 的版本进步。
咱们团队的小伙伴第一工夫也是这么干的,他去和业务团队的技术经理沟通,看他们能不能把 JDK8 调整成 JDK11,而后失去了业务团队技术经理的高度否定,因为他们大部分业务都跑在 jdk8,冒然升级成 jdk11,也不晓得会不会因为了解决一个问题,而引入其余问题
问题排查
因为这个 starter 的主动拆卸配置的内容绝对简略,基于老司机的第六感,问题大概率是呈现在 @ConditionalOnClass 这注解上,于是点开 @ConditionalOnClass,他的注解上有如下提醒
他的粗心是,能够在 @Configuration classes 上平安地指定 value(),因为在加载类之前会应用 ASM 解析正文元数据。当搁置在 @Bean 办法上时,须要分外小心,请思考在独自的 Configuration 类中隔离条件,特地是当办法的返回类型与条件的指标匹配时。如果非要用办法注解,倡议应用 ConditionalOnClass 外面的 name 字段
于是咱们听官网的倡议,将 starter 调整如下
@Configuration
@EnableConfigurationProperties({ApolloRefreshProperties.class})
public class ApolloRefreshAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "com.ctrip.framework.apollo.ConfigService")
public ApolloRefreshService apolloRefreshService(ApolloRefreshProperties properties) {return new ApolloRefreshService(properties);
}
}
再次运行,果然不再报错。具体问题起因,我就不班门弄斧了,能够查看官网的 issue
https://github.com/spring-projects/spring-boot/issues/27846
https://github.com/spring-projects/spring-boot/issues/17282
总结
首先如果用 @ConditionalOnClass 注解, 强烈建议应用 name 属性 ,而不要用 value 属性。其次如果有提供组件给其余业务团队应用,要特地关注版本问题,以及做好向下兼容,不然指不定又掉坑了。