Spring源碼深度解析,Spring源碼以及組件,@Conditional 條件註冊Bean,@Import 註冊組件(四)(附代碼示例:)

四)初始Spring源碼以及常用組件

目錄

)初始Spring源碼以及常用組件

 一, @Conditional 註解

    4.1.1,什麼叫做條件註冊bean?

二, @Import註解 註冊組件

    4.2.1,給容器中註冊組件的方式:

三,項目 Demo地址


 

 一, @Conditional 註解

  • 條件註冊bean,根據指定條件選擇性地註冊bean實例

    4.1.1,什麼叫做條件註冊bean?

        模擬以下場景: 我在當操作系統爲  windows 的時候   @Bean(lison)實例, 而在linux的時候  @Bean("james")

      示例代碼 4.1.1:

    @Conditional(WinCondition.class)
	@Bean("lison")
	public Person lison(){
		System.out.println("給容器中添加lison.......");
		return new Person("Lison",58);
	}
	@Conditional(LinCondition.class)
	@Bean("james")//bean在容器中的ID爲james, IOC容器MAP,  map.put("id",value)
	public Person james(){
		System.out.println("給容器中添加james.......");
		return new Person("james",20);
	}

    

    @Conditional(WinCondition.class)     WinCondition.class 是我自己定義的一個過濾類,  這個需要實現 Condition  接口,

  在Spring 源碼中  拿到bean 的信息,  都是 通過  BeanFactory() , 而 註冊   都是通過  FactoryBean()   ,獲得操作 系統 可以通過 Spring 上下文,   也可以通過    System.getProperty("os.name") ,  裏面 的  參數 os.name  是定義好的

public class WinCondition implements Condition{

	
	
	/*
	*ConditionContext: 判斷條件可以使用的上下文(環境)
	*AnnotatedTypeMetadata: 註解的信息
	*
	*/
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO 是否爲WINDOW系統
		//能獲取到IOC容器正在使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//獲取當前環境變量(包括我們操作系統是WIN還是LINUX??)
		Environment environment = context.getEnvironment();
		String os_name = environment.getProperty("os.name");
		if(os_name.contains("Windows")){
			return true;
		}
		return false;
	}

}

@Conditional(LinCondition.class)

public class LinCondition implements Condition{

	
	
	/*
	*ConditionContext: 判斷條件可以使用的上下文(環境)
	*AnnotatedTypeMetadata: 註解的信息
	*
	*/
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO 是否爲WINDOW系統
		//能獲取到IOC容器正在使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//獲取當前環境變量(包括我們操作系統是WIN還是LINUX??)
		Environment environment = context.getEnvironment();
		String os_name = environment.getProperty("os.name");
		if(os_name.contains("linux")){
			return true;
		}
		return false;
	}

  進行測試,得到我們想要的結果:

 public void test01(){
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap7MainConfig.class);
        System.out.println("IOC容器創建完成.........");
        //app.getBean("person");//執行獲取的時候才創建並初始化bean
        String[] beanDefinitionNames = app.getBeanDefinitionNames();
		for(String name:beanDefinitionNames){
			System.out.println(name);
		}
    }

 

 

  lison 已經根據我們的條件注入bean

 

二, @Import註解 註冊組件

  • 手動添加組件到Ioc容器;
  • 使用 ImportSelector 自定義返回組件
  • 使用 ImportBeanDefinitionRegistrar返回自定義組件

    4.2.1,給容器中註冊組件的方式:

  •  @Bean   導入第三方的類或包的組件,比如 Person 爲第三方類,需要在我們的 IOC 容器 中使用,包掃描+組件的標註註解(@ComponentScan : @Contorller  @Service  @Reponsitory @Componet ,一般是針對我們自己寫的類,使用這個)
  • @Import : 快速給容器導入一個組件,注意: @Bean 有點簡單,
  •  @Import (要導入到容器中的組件) 容器會自動註冊這個組件,beanid爲全類名,
  • ImportSelector : 是一個接口,返回需要導入到容器的組件的全類名數組
  • ImportBeanDefinitionRegistrar : 可以手動添加組件到IOC容器,所有Bean的註冊可以使用BeanDefinitionRegeistry寫JamesImportBeanDefinitionRegistrar實現ImportBeanDefinitionRegistrar接口即可
  • 使用Spring提供的FactoryBean(工廠bean)進行註冊

   4.2.1 示例源碼: 定義   6 個類, 裏面沒有任何操作:見 項目源碼---》 cap6

         我們使用FactoryBean(工廠bean)進行註冊:   將上面我們新建的 Monkey 類  註冊到  工廠bean

public class JamesFactoryBean implements FactoryBean<Monkey>{

	@Override
	public Monkey getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Monkey();
	}

	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Monkey.class;
	}
	
	@Override
	public boolean isSingleton() {
		return true;
	}
}

 我們使用  ImportBeanDefinitionRegistrar  添加組件實現 ImportBeanDefinitionRegistrar  接口重寫 registerBeanDefinitions

方法 , AnnotationMetadata  參數 是當前類的註解信息, BeanDefinitionRegistry   即 BeanDefinition註冊類。 將 dog, cat 兩個類註冊到 容器中去

public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/*
	*AnnotationMetadata:當前類的註解信息
	*BeanDefinitionRegistry:BeanDefinition註冊類
	*    把所有需要添加到容器中的bean加入;
	*    @Scope
	*/
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean bean1 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Dog");
		boolean bean2 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Cat");
		//如果Dog和Cat同時存在於我們IOC容器中,那麼創建Pig類, 加入到容器
		//對於我們要註冊的bean, 給bean進行封裝,
		if(bean1 && bean2){
			RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
			registry.registerBeanDefinition("pig", beanDefinition);
		}
	}

 

@ImportSelectot 接口   返回的是一個數組, 裏面可以添加多個 類, 一起註冊到 容器中去,

public class JamesImportSelector implements ImportSelector{
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata){
		//返回全類名的bean
		return new String[]{"com.enjoy.cap6.bean.Fish","com.enjoy.cap6.bean.Tiger"};
	}
}

測試: -----》 項目源碼: cap6Test

@Test
	public void test01(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap6MainConfig.class);
		
		System.out.println("IOC容器創建完成........");
		
		//如果返回true,說明是單例,返回false,說明是多例。。
		Object bean1 = app.getBean("&jamesFactoryBean");
		Object bean2 = app.getBean("jamesFactoryBean");//取Money
		System.out.println("bean的類型="+bean1.getClass());
		System.out.println(bean1 == bean2);
		
		String[] beanDefinitionNames = app.getBeanDefinitionNames();
		for(String name:beanDefinitionNames){
			System.out.println(name);
		}

 

 

三,項目 Demo地址

Spring源碼深度解析,(附代碼示例 碼雲地址: https://gitee.com/Crazycw/SpringCode.git

參考資料:  https://docs.spring.io/spring/docs/4.3.18.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/

請看下篇: Spring源碼深度解析,初始Spring源碼----Bean 生命週期(五)(附代碼示例:)

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