我们经常会有根据条件来加载不同的接口。 Spring Boot 能根据不同的实际情况启用不同的配置。这就是@Conditional注解在发挥作用。该注解指定了在什么条件下创建 Bean 并进行装配。
一: @conditional
Spring Boot 包含多个 @Conditional 注释,可以在@Configuration注解的类和@Bean注解方法中使用。@Conditional类型的注解,可以注解在类上,可以注解在Bean方法上
1.1 Class Conditions
@ConditionalOnClass和@ConditionalOnMissingClass 两个用在类上的注解:
@ConditionalOnClass:判断指定的类在classpath下是否存在,如果存在则实例化该注解修饰的类,否则不实例化该注解所修饰的类
ConditionalOnMissingClass: 判断指定的类classpath下是否存在,如果不存在则实例化该注解修饰的类,否则不实例化该注解所修饰的类
@Configuration
@ConditionalOnClass({DruidDataSource.class})
public class DruidDataSourceAutoConfigure {
}
当classpath中存在DruidDataSource这个类的时候,spring才会实例化DruidDataSourceAutoConfigure这个类
1.2 Bean Conditions
@ConditionalOnBean和@ConditionalOnMissingBean 两个用在 Bean 方法上的注解:
@ConditionalOnBean:判断指定的Bean在ioc是否存在,如果存在则实例化该注解修饰的Bean,否则不实例化该注解所修饰的Bean
ConditionalOnMissingBean: 判断指定的Bean在ioc中是否存在,如果不存在则实例化该注解修饰的Bean,否则不实例化该注解所修饰的Bean
@Configuration
public class ConditionBeanTest {
@Bean
public Boss createBean(){
return new Boss();
}
@Bean
@ConditionalOnBean(Boss.class)
public BossBackup createBackupBean(){
return new BossBackup();
}
}
只有当Boss这个Bean被创建后,spring才会实例化BossBackup这个Bean
1.3 Property Conditions
@ConditionalOnProperty注解可以基于Spring Environment属性包含的配置进判断,再决定自动配置的执行,使用 prefix 和 name 属性指定检查application.properties/application.yml配置文件的属性值。
@Configuration
public class ConditionBeanTest {
@Bean
@ConditionalOnProperty(prefix="app",name = "test", havingValue = "true")
public Boss createBean1(){
return new Boss();
}
}
只有配置文件中设置了app.test=true时候才会创建Boss这个类
1.4 Resource Conditions
@ConditionalOnResource当指定的资源文件出现在classpath特时执行自动配置
@Configuration
public class ConditionBeanTest {
@Bean
@ConditionalOnResource(resources="classpath:boss.ini")
public Boss createBean2(){
return new Boss();
}
}
当在classpath下发现了boss.ini文件时候,实例化Boss
1.5 Web Application Conditions
@ConditionalOnWebApplication和@ConditionalOnNotWebApplication注解用于判断应用程序是否为Web应用程序。
@Configuration
public class ConditionBeanTest {
@Bean
@ConditionalOnWebApplication
public BossBackup createBossBackup(){
return new BossBackup();
}
}
当我们的应用程序是Web Application时候,创建BossBackup这个类
1.6 SpEL Expression Conditions
@ConditionalOnExpression注解根据SpEL表达式的结果来执行配置。如果满足表达式的结果执行配置,否则不执行配置
@Configuration
public class ConditionBeanTest {
@Bean
@ConditionalOnExpression("#{'true'.equals(environment.getProperty('app.isEnableBackup'))}")
public BossBackup createBossBackup1(){
return new BossBackup();
}
}
上面的配置就是代表党配置文件中设置了app.isEnableBackup 属性并设置为true时,才开始实例化BossBackup这个类,也可以这样写
@Bean
@ConditionalOnExpression("#{!'false'.equals(environment.getProperty('app.isEnableBackup'))}")
public BossBackup createBossBackup2(){
return new BossBackup();
}
二:自定义 Condition
如果上面几种都不能满足你的需要。那么我们可以通过实现Condition接口,并重写其matches方法来构造判断条件。
比如我们需要依赖配置文件中的条件决定是否开启Spring 自带的一些Enable注解(@EnableScheduling,@EnableAsync)然后通过condition接口来实现。@EnableScheduling,@EnableAsync的选择性启动。
1:定义ShouldEnableSchedule 类并实现condition接口
public class ShouldEnableSchedule implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
String v = conditionContext.getEnvironment().getProperty("app.isEnableSchedule");
return v.equals("enable");
}
}
2:创建一个条件配置configuration类,当满足matches条件创建,并在配置类上添加@EnableScheduling, @EnableAsync注解
@Configuration
@Conditional(ShouldEnableSchedule.class)
@EnableScheduling
@EnableAsync
public class EnableScheduleConfig {
}
3:创建一个任务类
@Component
public class DeviceHealthTask {
@Autowired
private ActuatorDetail actuatorDetail;
@Scheduled(cron = "*/1 * * * * ?")
public void getHealthStatusInfo(){
this.actuatorDetail.getHealthDetailByJmx();
this.actuatorDetail.startMyTreadTask();
for (int i=0;i < 20;i++){
System.out.println("DDDDDD");
}
}
}
同时把actuatorDetail.startMyTreadTask()修饰为异步任务
@Service
public class ActuatorDetail {
@Async
public void startMyTreadTask() {
for (int j=0;j< 20;j++) {
System.out.println("this is my async task");
}
}
public void getHealthDetailByJmx() {
System.out.println("#######@@@@@@@@@@$$$$$$$$$4");
}
}
4:运行spring 程序
从执行结果可以看到,定时任务启动了,并且方法startMyTreadTask是异步执行的。