SpringBoot @Bean 和 @ConditionalOnClass 同时使用(如何实现存在指定类型时才注入某个 Bean)
有时候会希望存在指定类型时才注入某个 Bean(或者某个类型不存在时才注入某个 Bean):
@AutoConfiguration
public class MyAutoConfiguration {
@Bean
@ConditionalOnClass(MyService.class)
public MyConditionalBean statistics() {
return new MyConditionalBean();
}
// @Bean
// @ConditionalOnMissingBean(MyService.class)
// public MyConditionalBean statistics() {
// return new MyConditionalBean();
// }
}
但是如果按照上述代码,当MyService
不存在的时候,程序会直接找不到类,导致程序无法启动。
你会发现@ConditionalOnClass
用在被@Configuration
标注的类上,即使指定的类不存在,程序也会正常启动。但是像上面那样就不行。
这是因为和@Configuration
一起使用@ConditionalOnClass
时,其注解信息通过 ASM 解析,但是在处理和@Bean
一起用的@ConditionalOnClass
时,所在的配置类已经被 JVM 加载了,也就是加载在解析的前面,而要加载成功,首先要能够找到@ConditionalOnClass
所指明的类。
解决方法
-
指定全类名
@Bean @ConditionalOnClass(name ="com.example.MyService") public MyConditionalBean statistics() { return new MyConditionalBean(); }
-
内嵌配置类
@AutoConfiguration public class MyAutoConfiguration { @Configuration @ConditionalOnClass(MyService.class) public class MyConfiguration { @Bean public MyConditionalBean statistics() { return new MyConditionalBean(); } } }
-
创建一个单独的配置类,其实和内置配置类类似,只是将配置类拿了出来
@AutoConfiguration @ConditionalOnClass(MyService.class) public class MyAutoConfiguration2 { @Bean public MyConditionalBean statistics() { return new MyConditionalBean(); } }
参考:
Creating Your Own Auto-configuration :: Spring Boot
java - How does spring-boot @ConditionalOnClass work? - Stack Overflow