背景
假如现在有个jar包叫做A.jar,我想根据引用这个A.jar的项目是否有/无某些类,来决定加载是否加载A.jar的Bean
我们就可以考虑@ConditionalOnClass
或者ConditionalOnMissingClass
所以我们的代码会写成
@Configuration
public class AirOpenAutoConfiguration {
@ConditionalOnClass({CasHelper.class})
@ConditionalOnMissingBean(name = "airOpenAuthenticationFilter")
@Configuration
public class OpenCasAuthentication {
@Bean("airOpenAuthenticationFilter")
public FilterRegistrationBean<AirOpenAuthenticationFilter> airOpenAuthenticationFilterRegistration() {
FilterRegistrationBean<AirOpenAuthenticationFilter> filter = new FilterRegistrationBean<>();
return filter;
}
}
要点1:加入true
这里我们判断是否有CasHelper.class
这个类,有的话就创建这个bean,这个CasHelper
类是在另外一个jar包里面的。所以我们需要引入了这个,但是只能是是A.jar引用,不能传递到下去。所以需要引入的时候改成这样
<dependency>
<groupId>com.xxx</groupId>
<artifactId>cas</artifactId>
<scope>compile</scope>
<optional>true</optional>
</dependency>
这里一定要带上<optional>true</optional>
,这样依赖就不会传递下去。只保证A.jar里面是有这个CasHelper
,比如有个项目B引入了这个A.jar,假如B没有引入cas
这个包,那么这个CasHelper
将会不存在与B的项目中,这时
@ConditionalOnClass({CasHelper.class})会判定CasHelper
不存在,然后不加载这个airOpenAuthenticationFilter
的Bean。
要点2:@ConditionalOnClass需要配合@Configuration使用,不与@Bean配合使用
假如我们是这样写的
@Configuration
public class AirOpenAutoConfiguration {
@ConditionalOnClass({CasHelper.class})
@ConditionalOnMissingBean(name = "airOpenAuthenticationFilter")
@Bean("airOpenAuthenticationFilter")
public FilterRegistrationBean<AirOpenAuthenticationFilter> airOpenAuthenticationFilterRegistration() {
FilterRegistrationBean<AirOpenAuthenticationFilter> filter = new FilterRegistrationBean<>();
return filter;
}
也就是将注解放在方法上面,并且和@Bean一起使用,这个时候就会出现这个报错sun.reflect.annotation.TypeNotPresentExceptionProxy
Using the @ConditionalOnClass annotation in the method results in "java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy"
所以在我们使用@ConditionalOnXXX
相关的注解时候,最好是用对这个bean再封装一层@Configuration
,然后再这个Configuration上面去使用@ConditionalOnXXX
,这个也是官方的建议,所以我们需要遵循这个来。
类似以下:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JobLauncher.class, DataSource.class })
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
@ConditionalOnBean(JobLauncher.class)
@EnableConfigurationProperties(BatchProperties.class)
@Import(BatchConfigurerConfiguration.class)
public class BatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ExitCodeGenerator.class)
public JobExecutionExitCodeGenerator jobExecutionExitCodeGenerator() {
return new JobExecutionExitCodeGenerator();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(DataSource.class)
@ConditionalOnClass(DatabasePopulator.class)
static class DataSourceInitializerConfiguration {
@Bean
@ConditionalOnMissingBean
BatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource,
@BatchDataSource ObjectProvider<DataSource> batchDataSource, ResourceLoader resourceLoader,
BatchProperties properties) {
return new BatchDataSourceInitializer(batchDataSource.getIfAvailable(() -> dataSource), resourceLoader,
properties);
}
}
}