1. 程式人生 > >Spring中的@conditional註解

Spring中的@conditional註解

gist names auth als context cond load ica 2018年

今天主要從以下幾方面來介紹一下@Conditional註解

  • @Conditional註解是什麽

  • @Conditional註解怎麽使用

1,@Conditional註解是什麽

@Conditional註解是可以根據一些自定義的條件動態的選擇是否加載該bean到springIOC容器中去,如果看過springBoot源碼的同學會發現,springBoot中大量使用了該註解

2,@Conditional註解怎麽使用

查看@Conditional源碼你會發現它既可以作用在方法上,同時也可以作用在上,源碼如下:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    /**
     * All {@link Condition}s that must {@linkplain Condition#matches match}
     * in order for the component to be registered.
     */
    Class<? extends Condition>[] value();
}

設置給@conditional的類需要實現Condition接口

我們看一下Condition的源碼:

public interface Condition {
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}



ConditionContext源碼:

public interface ConditionContext {
    BeanDefinitionRegistry getRegistry();

    ConfigurableListableBeanFactory getBeanFactory();

    Environment getEnvironment();

    ResourceLoader getResourceLoader();

    ClassLoader getClassLoader();
}



AnnotatedTypeMetadata源碼:

此類能夠讓我們檢查帶有@Bean註解的方法上還有其他什麽註解

public interface AnnotatedTypeMetadata {
    boolean isAnnotated(String var1);

    Map<String, Object> getAnnotationAttributes(String var1);

    Map<String, Object> getAnnotationAttributes(String var1, boolean var2);

    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1);

    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1, boolean var2);
}

a,@Conditional作用在方法上

定義一個Condition如下:

/**
 * 定義一個bean的Condition
 *
 * @author zhangqh
 * @date 2018年5月1日
 */
public class MyCondition implements Condition {
    public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        String system = env.getProperty("os.name");
        System.out.println("系統環境為 ==="+system);
        // 系統環境在Windows才加載該bean到容器中
        if(system.contains("Windows")){
            return true;
        }
        return false;
    }
}


定義一個bean加上@Conditional註解如下:

@Conditional({MyCondition.class})
@Bean(value="user1")
public User getUser1(){
    System.out.println("創建user1實例");
    return new User("李四",26);
}

測試如下:

AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanNames = applicationContext2.getBeanDefinitionNames();
for(int i=0;i<beanNames.length;i++){
    System.out.println("bean名稱為==="+beanNames[i]);
}

運行結果:

bean名稱為===mainConfig
bean名稱為===user0
bean名稱為===user1

我這邊電腦系統是window所以user1實例是有創建出來的,如果把MyCondition中的判斷改成if(system.contains("linux"))那麽user1是不會加載到spring容器中的

b,@Conditional作用在類上

修改註解配置如下:

/**
 * 定義一個註解配置文件 必須要加上@Configuration註解
 *
 * @author zhangqh
 * @date 2018年4月30日
 */
@Conditional({MyCondition.class})
@Configuration
public class MainConfig {
    /**
     * 定義一個bean對象
     * @return
     */
    @Scope
    @Lazy
    @Bean(value="user0")
    public User getUser(){
        System.out.println("創建user實例");
        return new User("張三",26);
    }
    //@Conditional({MyCondition.class})
    @Bean(value="user1")
    public User getUser1(){
        System.out.println("創建user1實例");
        return new User("李四",26);
    }
}

運行測試:

bean名稱為===mainConfig
bean名稱為===user0
bean名稱為===user1

MainConfig中的bean都成功打印出來了,因為我MyCondition條件返回的是true,同樣如果我修改成if(system.contains("linux"))那麽MainConfig的bean就都不會實例化了

c, @profile註解分析

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({ProfileCondition.class})
public @interface Profile {
    String[] value();
}

註意:@Profile本身也使用了@Condition註解,並且引用ProfileCondition作為Condition的實現。

以下為ProfileCondition的實現

class ProfileCondition implements Condition {
    ProfileCondition() {
    }

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (context.getEnvironment() != null) {
            MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
            if (attrs != null) {
                Iterator var4 = ((List)attrs.get("value")).iterator();

                Object value;
                do {
                    if (!var4.hasNext()) {
                        return false;
                    }

                    value = var4.next();
                } while(!context.getEnvironment().acceptsProfiles((String[])((String[])value)));

                return true;
            }
        }

        return true;
    }
}

Spring中的@conditional註解