本文為博主原創,轉載請注明 出處:
一。@Conditional注解作用:
必須是 @Conditional 注解指定的條件成立,才會在容器中添加組件,配置類里面的所有配置才會生效
二。@Conditional 衍生注解
@Conditional擴展注解作用 | 判斷是否滿足指定條件 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean; |
@ConditionalOnClass | 系統中有指定的類 |
@ConditionalOnMissingClass | 系統中沒有指定的類 |
@ConditionalOnProperty | 系統中指定的屬性是否有指定的值 |
@ConditionalOnResource | 類路徑下是否存在指定資源文件 |
@ConditionalOnWebApplication | 當前是web環境 |
三。@Conditional注解 的使用
3.1 @Conditional 注解源碼解析
@Conditional 注解源碼:
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class<? extends Condition>[] value(); }
通過源碼可以發現看到該注解的傳參值 為一個數組,並且需要繼承 Condition 類。
查看 Condition 類的源碼:
@FunctionalInterface public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); }
Condition 為一個函數式接口,其中只有一個matches 方法,接口的返回類型為boolean 值,通過該boolean 值控制是否加載配置。
3.2 @Conditional 實現控制bean 加載
1. 創建一個bean的實體類:
@Data @AllArgsConstructor public class Person { private String name; private int age; }
2. 通過 @Configuration 注解定義兩個person 的bean
@Configuration public class BeanConfiguration { @Bean(name= "java") public Person person1(){ return new Person("java",12); } @Bean(name= "linux") public Person person2(){ return new Person("linux",22); } }
3. 通過單元測試查看兩個bean
@SpringBootTest class TestApplicationTests { @Autowired private ApplicationContext applicationContext; @Test void contextLoads() { Map<String, Person> personBeanMap = applicationContext.getBeansOfType(Person.class); personBeanMap.forEach((beanName, beanValue) -> { System.out.println(beanName + "--" + beanValue); }); } }
通過這個單元測試會打印出兩行Person bean 的信息
4. 定義 實現 Condition 接口的類,並控制是否加載。
import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { Environment environment = conditionContext.getEnvironment(); String property = environment.getProperty("os.name"); if (property.contains("linux")){ return true; } return false; } }
並在定義Bean 的BeanConfiguration 類中使用 @Condition 注解實現bean 是否加載
import com.example.test.entity.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class BeanConfiguration { @Bean(name= "java") public Person person1(){ return new Person("java",12); } @Conditional(WindowsCondition.class) @Bean(name= "linux") public Person person2(){ return new Person("linux",22); } }
5.執行單元測試:
import com.example.test.entity.Person; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import java.util.Map; @SpringBootTest class TestApplicationTests { @Autowired private ApplicationContext applicationContext; @Test void contextLoads() { Map<String, Person> personBeanMap = applicationContext.getBeansOfType(Person.class); personBeanMap.forEach((beanName, beanValue) -> { System.out.println(beanName + "--" + beanValue); }); } }
運行之后只會打印 person1 這個bean 的信息。
四。@ConditionalOnProperty 注解的使用
該注解經常用來管理配置文件中的某些配置開關,比如 中間件 通過這個配置判斷是否進行加載。
查看 @ConditionalOnProperty 注解源碼
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Conditional; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional({OnPropertyCondition.class}) public @interface ConditionalOnProperty { String[] value() default {}; String prefix() default ""; String[] name() default {}; String havingValue() default ""; boolean matchIfMissing() default false; }
value : String數組 該屬性與下面的 name 屬性不可同時使用,當value所對應配置文件中的值為false時,注入不生效,不為fasle注入生效
prefix :配置文件中key的前綴,可與value 或 name 組合使用
name :與 value 作用一致
havingValue : 與value 或 name 組合使用,只有當value 或 name 對應的值與havingValue的值相同時,注入生效
matchIfMissing :該屬性為true時,配置文件中缺少對應的value或name的對應的屬性值,也會注入成功
使用示例:
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnProperty(prefix = "redis.config",value = "enabled",havingValue = "true") public class RedisConfiguration { }
在application.yml 配置文件配置:
redis.config.enabled=true
當 redis.config.enabled 值為 true時,會加載該類的配置,若只為false,則不加載。
通過這種方式,可以很好的控制一些功能在不同環境上的開發性和使用性。