四、Spring-bean組件註冊

給容器中註冊組件,有下面這幾種方式
1)、包掃描+組件標註註解(@Controller/@Service/@Repository/@Component)
2)、@Bean 
3)、@Import
4)、使用Spring提供的 FactoryBean(工廠Bean);java

前兩種在前面的博文中已經介紹了,本博文就只介紹後面的兩種方式。linux

 

一、註解@Importspring

配置類:windows

@Configuration
@Import({User.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class RegisterBeanConfig {
    //AccountFactoryBean implements FactoryBean<Account>
    //spring會調用AccountFactoryBean裏的getObject獲取bean實例註冊到spring中
    @Bean
    public AccountFactoryBean accountFactoryBean(){
        return new AccountFactoryBean();
    }
}

首先看一下@Import數組

其中User.class指定註冊User類型的bean實例。app

public class User {
}

MyImportSelector這個類實現了ImportSelector方法,該方法返回一個數組,spring就會把數組裏的類經過反射的方式生成bean實例註冊到spring容器中,ide

bean實例的name爲全限定路徑名。測試

public class MyImportSelector implements ImportSelector{
    //返回值,就是到導入到容器中的組件全類名
    //AnnotationMetadata:當前標註@Import註解的類的全部註解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println(importingClassMetadata);
        //importingClassMetadata
        //方法不要返回null值
        return new String[]{"com.suzhe.spring.basic.registerbean.Car"};
    }
}
public class Car {
}

MyImportBeanDefinitionRegistrar這個類實現了ImportBeanDefinitionRegistrar接口中registerBeanDefinitions方法,該方法經過RootBeanDefinition類傳入了Person.class ,生成RootBeanDefinition對象,並調用registerBeanDefinition方法將Person類型的bean組件註冊到spring容器中。操作系統

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //指定Bean定義信息;(Bean的類型,Bean。。。)
        RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
        //註冊一個Bean,指定bean的name
        registry.registerBeanDefinition("person", beanDefinition);
    }
}
public class Person {

}

 

二、FactoryBean.net

再看一下AccountFactoryBean類,該類經過實現FactoryBean接口從新接口中的方法,spring會調用AccountFactoryBean裏的getObject獲取bean實例註冊到spring中。

//建立一個Spring定義的FactoryBean
public class AccountFactoryBean implements FactoryBean<Account> {

    //返回一個Color對象,這個對象會添加到容器中
    @Override
    public Account getObject() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("AccountFactoryBean...getObject...");
        return new Account();
    }

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

    //是單例?
    //true:這個bean是單實例,在容器中保存一份
    //false:多實例,每次獲取都會建立一個新的bean;
    @Override
    public boolean isSingleton() {
        // TODO Auto-generated method stub
        return true;
    }

}

測試運行

@Test
	public void test1(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(RegisterBeanConfig.class);
		//獲取容器中全部註冊的bean的name,返回一個數組
		String[] names = app.getBeanDefinitionNames();
		for(String name:names){
			System.out.println(name);
		}
	}

能夠看到對應的bean組件註冊到了spring容器中,值得注意的是user和car的name都是全路徑名,其次Account的name爲accountFactoryBean,這是因爲

@Bean默認會用方法名做爲bean實例的name。

 

咱們驗證一下經過accountFactoryBean的獲取bean實例類型是不是Accout。

@Test
	public void test2(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(RegisterBeanConfig.class);
		Object bean = app.getBean("accountFactoryBean");
		System.out.println(bean.getClass());
	}

經過運行結果能夠看出,經過accountFactoryBean的獲取bean的確是Accout

 

 

FactoryBean與BeanFactory比較:

BeanFactory:bean工廠,獲取bean實例的工廠。從下面的繼承關係圖能夠看出spring容器(AnnotationConfigApplicationContext)實現了BeanFactory接口,該接口裏定義了若干getBean方法,能夠獲取bean實例。

 

FactoryBean:工廠bean,產生某個類型bean組件的工廠。

 

三、條件註解@Conditional

在註冊bean的時候還能夠添加條件判斷,符合條件才註冊對應的bean實例,好比下面的配置,若是是linux環境則注入Person 組件,若是是windows環境,則注入Car組件。值得注意的是若是配置在類上,知足條件,這個類中配置的全部bean註冊才能生效;

@Configuration
//@Conditional(LinCondition.class)//類中組件統一設置。知足當前條件,這個類中配置的全部bean註冊才能生效;
public class RegisterConditionConfig {
    @Bean
    @Conditional(LinCondition.class)
    public Person person(){
        return new Person();
    }
    @Bean
    @Conditional(WinCondition.class)
    public Car car(){
        return new Car();
    }

}

LinCondition和WinCondition分別實現了Condition接口 ,並實現了matches方法,返回true,則容許註冊bean實例。

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 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;
	}

}

測試運行

@Test
	public void test3(){
		AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(RegisterConditionConfig.class);
		//獲取容器中全部註冊的bean的name,返回一個數組
		String[] names = app.getBeanDefinitionNames();
		for(String name:names){
			System.out.println(name);
		}
	}

因爲程序是在windows環境運行的,能夠看出將Car註冊到了spring容器中。

相關文章
相關標籤/搜索