@Conditional注解使用及@ConditionalOnXXX各注解的作用


本文為博主原創,轉載請注明 出處:

一。@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,則不加載。

    通過這種方式,可以很好的控制一些功能在不同環境上的開發性和使用性。

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM