总结自:https://www.cnblogs.com/davidwang456/p/3688250.html
Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即xxxFactoryBean返回的bean。
工厂Bean跟普通Bean不同,其不是类的一个实例,而是xxxFactoryBean的getObject方法所返回的xxx的对象(通过getObject返回对象,这是工厂bean的核心!)。
如何创建bean?
传统方式,通过反射机制利用bean的class属性指定实现类来实例化bean,这需要大量配置,不甚灵活,
而通过工厂bean,我们能定制实例化bean的流程。
备注:FactoryBean是一个接口,而xxxFactoryBean是实现了FactoryBean的类,可以生成某一个类型Bean实例。
Spring 自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。
从Spring 3.0 开始, FactoryBean开始支持泛型,即接口声明改为FactoryBean<T> 的形式:
package org.Springframework.beans.factory; public interface FactoryBean<T> { T getObject() throws Exception; Class<?> getObjectType(); boolean isSingleton(); }
方法介绍:
T getObject():返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。
boolean isSingleton():返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。
Class<T> getObjectType():返回FactoryBean创建的bean类型。
当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过 getBean()方法返回的不是FactoryBean的实例,而是FactoryBean的getObject()方法所返回的对象,
这相当于FactoryBean的getObject()代理了getBean()方法。
如何体现factoryBean的灵活?
例如:如果使用传统方式配置下面Car的<bean>时,Car的每个属性分别对应一个<property>元素标签
public class Car { private int maxSpeed ; private String brand ; private double price ; //get/set方法... }
如果使用factoryBean
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; } }
个人理解,在设值时能有更多的个人操作,相当于通用版和定制化的区别。
那么相应的,我们应当这么配置:
<bean id="car" class="com.test.factorybean.CarFactoryBean" carInfo="超级跑车,400,2000000"/>
注意,这是工厂bean定义bean的一般形式。
当调用getBean("car") 时,Spring首先通过反射机制,发现CarFactoryBean实现了FactoryBean的接口,
然后调用getObject()方法返回定制的car实例。
备注:如果单纯希望获取CarFactoryBean的实例,则需要在使用getBean(beanName) 方法时在beanName前显示的加上 "&" 前缀,例如getBean("&car")。