BeanFactory:以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及创建这些对象间的依赖。git
Spring为咱们提供了许多易用的BeanFactory实现,XmlBeanFactory就是经常使用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个彻底可配置的系统或应用。github
通常状况下,Spring经过反射机制利用bean的class属性指定实现类来实例化bean。在某些状况下,实例化bean过程比较复杂,若是按照传统的方式,则须要在<bean>中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会获得一个简单的方案。Spring为此提供了一个org.Springframework.bean.factory.FactoryBean的工程类接口,用户能够经过实现接口定制实例化bean的逻辑。spring
FactoryBean接口对于Spring框架来讲占有重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改成FactoryBean<T>的形式:服务器
Resource resource = new FileSystemResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource); ClassPathResource resource = new ClassPathResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(resource); ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml", "applicationContext-part2.xml"}); BeanFactory factory = (BeanFactory) context;
基本就是这些了,接着使用getBean(String beanName)方法就能够取得bean的实例;BeanFactory提供的方法及其简单,仅提供了六种方法供客户调用:mybatis
这些定义的接口方法勾画了IoC容器的基本特性,由于BeanFactory接口定义了IoC容器。app
FactoryBean:以Bean结尾,表示它是一个Bean,不一样于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的其实是FactoryBean的getObject()返回的对象,而不是FactoryBean自己,若是要获取FactoryBean对象,请在id前面加一个&符号来获取。框架
FactoryBeandom
下面展现了FactoryBean提供的接口方法,须要注意的是,在Spring中为咱们实现了大量的FactoryBean,因此能够看出FactoryBean是很是重要的。this
通常状况下,Spring经过反射机制利用bean的class属性指定实现类来实例化bean。在某些状况下,实例化bean过程比较复杂,若是按照传统的方式,则须要在<bean>中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会获得一个简单的方案。Spring为此提供了一个org.Springframework.bean.factory.FactoryBean的工程类接口,用户能够经过实现接口定制实例化bean的逻辑。编码
FactoryBean接口对于Spring框架来讲占有重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改成FactoryBean<T>的形式:
package org.springframework.beans.factory; public interface FactoryBean<T> { T getObject() throws Exception; Class<?> getObjectType(); boolean isSingleton(); }
FactoryBean概念和接口在Spring框架中大量使用。Spring内置的有超过70个实现。
当配置文件中<bean>的class属性配置的实现类是FactoryBean时,经过getBean()方法返回的不是FactoryBean自己,而是FactoryBean#getBean()方法所返回的对象,至关于FactoryBean#getObject()代理了getBean()方法。
例如:若是使用传统方式配置下面Car的<bean>时,Car的每一个属性分别对应一个<property>元素标签。
public class Car{ private int maxSpeed; private String brand; private double price; //get set方法 }
若是用FactoryBean的方式实现就会灵活一些,下例经过逗号分割符的方式一次性地为Car的全部属性指定配置值:
public class CarFactoryBean implements FactoryBean<Car>{ private String carInfo; public Car getObject() throws Exception{ Car car = new Car(); String[] infos = carInfo.split(","); car.setBrand(infos[0]); car.setMaxSpeed(Integer.valueOf(infos[1])); car.setPrice(Double.valueOf(infos[2])); return car; } public Class<Car> getObjectType(){ return Car.class; } public boolean isSingleton(){ return false; } public String getCarInfo(){ return this.carInfo; } public void setCarInfo(Stirng carInfo){ this.carInfo = carInfo; } }
有了这个CarFactoryBean后,就能够在配置文件中使用下面这种自定义的配置方式配置CarBean了:
<bean id="car" class="com.test.factorybean.CarFactoryBean" carInfo="超级跑车,400,100000" />
当调用getBean("car")时,Spring经过反射机制发现CarBeanFactory实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean#getObject()方法返回。若是但愿获取CarFactoryBean的实例,则须要在使用getBean(beanName)方法时在beanName前显示的加上"&"前缀,例如getBean("&car")。
FactoryBean 一般是用来建立比较复杂的bean,通常的bean 直接用xml配置便可,但若是一个bean的建立过程当中涉及到不少其余的bean 和复杂的逻辑,用xml配置比较困难,这时能够考虑用FactoryBean。
若是你们有看过Mybatis的SessionFactoryBean和Activiti初始化引擎的ProcessEngineFactoryBean两个类就应该了解FactoryBean的具体使用。
不少开源项目在集成Spring 时都使用到FactoryBean,好比 MyBatis3 提供 mybatis-spring项目中的 org.mybatis.spring.SqlSessionFactoryBean
:
<bean id="tradeSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="trade" /> <property name="mapperLocations" value="classpath*:mapper/trade/*Mapper.xml" /> <property name="configLocation" value="classpath:mybatis-config.xml" /> <property name="typeAliasesPackage" value="com.bytebeats.mybatis3.domain.trade" /> </bean>
org.mybatis.spring.SqlSessionFactoryBean
以下:
package org.mybatis.spring; public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class); ...... }
FactoryBean的功能貌似更像是一种代理,有一种场景是,咱们使用一个通用的类来在xml文件中注册bean,咱们但愿经过该通用bean产生一个咱们但愿的bean,而这个需求FactoryBean就能够办到,你只须要拦截你须要代理的bean,而后转换成你但愿的bean再注册。一个应用场景就是Rpc服务器端的bean注册,以及Rpc客户端的服务调用,均可以经过一个第三方bean来产生咱们真正须要的bean。
当xml的配置文件中<bean>的class属性配置的实现类是FactoryBean时(以下面配置文件"bean id="car"),经过 getBean()方法返回的不是FactoryBean自己,而是FactoryBean.getObject()方法所返回的对象,至关于FactoryBean.getObject()代理了getBean()方法。例如:若是使用传统方式配置下面Car的<bean>时,Car的每一个属性分别对应一个<property>元素标签。
public class Car { private int maxSpeed ; private String brand ; private double price ; //get/set方法 }
对应Car在xml中的配置:
<bean id="car" class="com.dxz.demo.Car"> <property name="maxSpeed"> <value>100</value> </property> <property name="brand"> <value>红旗</value> </property> <property name="price"> <value>999999</value> </property> </bean>
若是用FactoryBean的方式实现就会灵活一些,下例经过逗号分割符的方式一次性地为Car的全部属性指定配置值:
public class CarFactoryBean implements FactoryBean<Car> { private String carInfo ; public Car getObject() throws Exception { Car car = new Car() ; String [] infos = carInfo .split ( "," ) ; car.setBrand ( infos [ 0 ]) ; car.setMaxSpeed ( Integer. valueOf ( infos [ 1 ])) ; car.setPrice ( Double. valueOf ( infos [ 2 ])) ; return car; } public Class<Car> getObjectType() { return Car. class ; } public boolean isSingleton() { return false ; } public String getCarInfo() { return this.carInfo ; } // 接受逗号分割符设置属性信息 public void setCarInfo( String carInfo ) { this.carInfocarInfo = carInfo; } }
有了这个CarFactoryBean后,就能够在配置文件中使用下面这种自定义的配置方式配置Car Bean了:
<bean id="car" class="com.dxz.demo.CarFactoryBean" carInfo="超级跑车,400,2000000"/>
当调用getBean("car") 时,Spring经过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean.getObject()方法返回。若是但愿获取CarFactoryBean的实例,则须要在使用getBean(beanName) 方法时在beanName前显示的加上 "&" 前缀,例如getBean("&car")。(当使用ApplicationContext的getBean()方法获取FactoryBean实例自己而不是它所产生的bean,则要使用&符号+id。好比,现有FactoryBean,它有id,在容器上调用getBean("myBean")将返回FactoryBean所产生的bean,调用getBean("&myBean")将返回FactoryBean它自己的实例。)