Spring Boot选择性装配 Condition

我们经常会有根据条件来加载不同的接口。 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 程序
image.png

从执行结果可以看到,定时任务启动了,并且方法startMyTreadTask是异步执行的。

你可能感兴趣的:(Spring Boot选择性装配 Condition)