背景
假如现在有个jar包叫做A.jar,我想根据引用这个A.jar的项目是否有/无某些类,来决定加载是否加载A.jar的Bean
我们就可以考虑@ConditionalOnClass或者ConditionalOnMissingClass
所以我们的代码会写成
@Configurationpublic class AirOpenAutoConfiguration {@ConditionalOnClass({CasHelper.class})@ConditionalOnMissingBean(name = "airOpenAuthenticationFilter")@Configurationpublic 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配合使用
假如我们是这样写的
@Configurationpublic 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@ConditionalOnMissingBeanBatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource,@BatchDataSource ObjectProvider<DataSource> batchDataSource, ResourceLoader resourceLoader,BatchProperties properties) {return new BatchDataSourceInitializer(batchDataSource.getIfAvailable(() -> dataSource), resourceLoader,properties);}}}
