spring5學習系列之------3 給容器註冊組件三 @Conditional 和 @Import 註解用法

     前文主要介紹了@bean  @ComponentScan 掃包注入兩種方式,今天介紹一下@Conditional按照條件注入和@import導入組件的相關用法

1 首先是@Conditional的用法:按照一定的條件進行判斷,滿足條件給容器中註冊bean,之前是寫了@bean註解就會注入,但是在bean上加了@Conditional註解,並不一定就會注入了,而是進行條件判斷之後再說,該註解在springboot源碼中大量用到,該註解是在spring4.0引入的。

  首先我們創建一個Config,並且在裏面註冊2個person的Bean其中一個爲windows另外一個爲linux,使用@Conditional註解來判斷當前操作系統是windows還是linux分別加載不同的bean,見下圖:

package com.study.chap4.conditional.config;
import com.study.chap4.conditional.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Conditional(WindowsCondition.class)
@Configuration
public class Config {
    /**
     * @Conditional({Condition}) : 按照一定的條件進行判斷,滿足條件給容器中註冊bean
     *
     * 如果系統是windows,給容器中註冊("windows")
     * 如果是linux系統,給容器中註冊("linux")
     */
    @Bean("windows")
    public Person person01(){
        return new Person("windows",18,"我是windows系統");
    }
    @Conditional(LinuxCondition.class)
    @Bean("linux")
    public Person person02(){
        return new Person("linux", 48,"我是linux系統");
    }
}

  我們看下@Conditional源碼可知,該註解可以用在類上和用在方法上,我們分別創建判斷的條件類WindowsCondition,linuxCondition,這裏爲了節約空間,就只貼出一個類的代碼

package com.study.chap4.conditional.config;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
 *  判斷是否是windows系統
 *
 * */
public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        return property.contains("Windows");
    }
}

 然後再測試類上面輸出所有注入的bean,由於系統運行是windows環境,所以windows的bean被注入,而linux沒有

import com.study.chap4.conditional.config.Config;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainTest4 {
    @Test
    public void demoChap3(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}

  2  使用@import註解快速給容器導入一個組件,觀察import源碼可知,該註解在spring3.0就有了,並且還可以link# ImportSelector:返回需要導入的組件的全類名數組;以及 ImportBeanDefinitionRegistrar:手動註冊bean到容器中

因此,我們首先直接用import的用法,直接導入組件名

package com.study.chap4.imports;
import com.study.chap4.imports.pojo.Blue;
import com.study.chap4.imports.pojo.Red;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({Red.class, Blue.class})
//@Import導入組件,默認是組件名是全類名
public class Config {
}

   輸出可見

   

   再用一種方式,ImportSelector:返回需要導入的組件的全類名數組,並且再springboot的啓動類中有用到這個特性,新建一個MyImportSelector去實現 ImportSelector 接口。

package com.study.chap4.imports;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    /**
     * @param importingClassMetadata  當前標註@Import註解的類的所有註解信息
     * @return 返回值,就是到導入到容器中的組件全類名
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.study.chap4.imports.pojo.Yellow"};
    }
}

   再使用第三種方式  ImportBeanDefinitionRegistrar:手動註冊bean到容器中,ImportBeanDefinitionRegistrar在springboot啓動類中也有用到,稍後進行分析一下。

package com.study.chap4.imports;
import com.study.chap4.imports.pojo.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:當前類的註解信息
     * BeanDefinitionRegistry:BeanDefinition註冊類;裏面有很多方法,註冊一個bean,移除一個bean等等
     * 		把所有需要添加到容器中的bean;調用
     * 		BeanDefinitionRegistry.registerBeanDefinition手工註冊進來
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        boolean definition = registry.containsBeanDefinition("com.study.chap4.imports.pojo.Red");
        boolean definition2 = registry.containsBeanDefinition("com.study.chap4.imports.pojo.Blue");
        if(definition && definition2){
            //指定Bean定義信息;(Bean的類型,Bean。。。)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
            //註冊一個Bean,指定bean名
            registry.registerBeanDefinition("rainBow", beanDefinition);
            //移除一個bean
            registry.removeBeanDefinition("config");
        }
    }

}

 

   至此,最後我們輸出可知: config確實被移除掉了。

     至此我們又新學了兩個註解的用法,一個是@Conditional 另外一個是@Import,其實spring以及springboot底層都是大量運用註解寫的相關代碼,充分利用了註解的特性,我們把這些註解會用並且弄懂,之後看源碼也不會覺得太吃力。

------------------------------------------------------------------------------------------------------------------------------------------------------------------

   這裏順便分析一個springboot啓動用到的這個特性,我們首先查看springboot的啓動類註解@SpringBootApplication源碼,當然springboot源碼啓動有很多,這裏不會給大家全部分析完畢,只會對用到的@import註解特性的進行分析。

 會看到裏面有3個註解,一個是@ComponentScan的自定義過濾條件的掃包注入容器,該註解在本人該系列第二篇博客中完整的詳細的解釋到了,這裏就不做過多的解釋。spring5學習系列之------2 給容器註冊組件二 @ComponentScan 自定義掃描規則,過濾組件接下來看第二個註解 @SpringBootConfiguration接着點進去

這是對 @Configuration註解的進行封裝,在看一個註解是 @EnableAutoConfiguration ,打開這個註解的源碼可看到

 重點來了,會看到一個@import註解,並且指定了一個導入的類,我們點進去,會看到用到了import的第二種方式

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章