四、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容器中。

相关文章
相关标签/搜索