在Spring中,有两个很容易混淆的类:BeanFactory和FactoryBean。前者是Factory也就是IOC容器或对象工厂,后者是Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对于FactoryBean而言,这个Bean不是简单的Bean,而是一个能产生或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
BeanFactory:Bean工厂,是一个工厂(Factory),我们Spring IoC容器的最顶层接口就是这个BeanFactory,它的作用是管理Bean,即实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
FactoryBean:工厂Bean,是一个Bean,作用是产生其他bean实例。通常情况下,这种bean没有什么特别的要求,仅需要提供一个工厂方法,该方法用来返回其他bean实例。通常情况下,bean无须自己实现工厂模式,Spring容器担任工厂角色;但少数情况下,容器中的bean本身就是工厂,其作用是产生其它bean实例。
FactoryBean是一个编程协议,实现不应该依赖于注解驱动的注入或其他反射功能。
当用户使用容器本身时,可以使用转义字符”&”
来得到FactoryBean本身,以区别通过FactoryBean产生的实例对象和FactoryBean对象本身。在BeanFactory中通过如下代码定义了该转义字符:
StringFACTORY_BEAN_PREFIX = "&";
如果myJndiObject是一个FactoryBean,则使用&myJndiObject
得到的是myJndiObject对象,而不是myJndiObject产生出来的对象。
【1】FactoryBean
工厂 Bean 跟普通Bean不同, 其返回的对象不是指定类的一个实例, 其返回的是该工厂 Bean 的 getObject 方法所返回的对象。
实现实例
public class CarFactoryBean implements FactoryBean<Car>{
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
// 核心方法实现实例,这里返回一个Car实例
public Car getObject() throws Exception {
return new Car(brand, 500000.0);
}
public Class<?> getObjectType() {
return Car.class;
}
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
FactoryBean<T>
接口源码
实现该接口的bean,将会被作为一个工厂用来暴露某个对象(不是暴露自己哦)。当然,实现了该接口的bean也可以被作为一个正常bean。FactoryBean是以bean样式定义的,但是其getObject()方法暴露的对象是其创建的对象,通常非自身。
public interface FactoryBean<T> {
//属性类型,可以在BeanDefinition中被AttributeAccessor#setAttribute方法设置,
//以便工厂bean在无法从工厂bean类推导出对象类型时,可以发出其对象类型的信号
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
FactoryBeans 可以支持singleton 和 prototype,同样也可以根据需要在启动时创建对象或者在需要时实例化对象(懒加载)。SmartFactoryBean接口允许暴露更多细粒度的行为元数据。
这个接口在框架中被大量使用,比如AOP(org.springframework.aop.framework.ProxyFactoryBean)或者org.springframework.jndi.JndiObjectFactoryBean
。同样可以用于自定义组件,然后其仅适用于基础架构代码。
FactoryBean是一个编程协议,实现不应该依赖于注解驱动的注入或其他反射功能。
getObjectType()或者getObject()方法可能在项目启动引导过程的早期就被调用,甚至在任何后处理器设置之前。如果需要访问其他bean,请实现BeanFactoryAware,并以编程方式获取它们。
最后,FactoryBean对象参与包含BeanFactory的bean创建同步。通常不需要进行内部同步,只是为了在FactoryBean本身(或类似对象)内进行延迟初始化。
getObject方法说明
返回工厂管理的对象实例(共享或者独立的),支持Singleton 和Prototype 作用域。如果调用时此FactoryBean尚未完全初始化(例如,因为它涉及循环引用),将会抛出FactoryBeanNotInitializedException异常。从Spring2.0开始,FactoryBeans 允许返回null对象。该工厂认为其会作为一个正常值被使用而不再抛出FactoryBeanNotInitializedException
异常。
实现FactoryBean 接口的类被鼓励在适当时机抛出FactoryBeanNotInitializedException 异常。
getObjectType方法说明
返回该工厂Bean创建的对象的类型,如果事先不知道将会返回null。这允许在不实例化对象的情况下检查特定类型的bean,例如在自动注入上。对于正在创建单例对象的实现,此方法应尽量避免单例创建,它应该提前预估对象类型。
对于原型,在这里返回有意义的类型也是可取的。该方法可以在bean完全实例化前被调用。它不能依赖于初始化期间创建的状态;当然,如果可用,它仍然可以使用这种状态。
注意:自动注入将会忽略getObjectType方法返回null的FactoryBeans 。因此,强烈建议使用FactoryBean的当前状态正确实现此方法。
boolean isSingleton()方法说明
返回当前FactoryBean管理的对象是否为singleton。如果是,则getObject()方法将会返回一样的对象。注意,如果一个FactoryBean 声明其拥有一个singleton 对象,从getObject()
方法返回的对象可能会被拥有的BeanFactory缓存。因此不建议该方法返回true,触发FactoryBean 永远暴露一样的对象引用。
FactoryBean本身的单例状态通常由拥有它的BeanFactory提供;通常,它必须被定义为singleton。
注意,该方法返回false不一定表示返回的对象是独立实例。该接口的实现SmartFactoryBean可能明确声明独立实例通过它的isPrototype()
方法。
如果isSingleton方法返回 false,则不实现此扩展接口的普通 FactoryBean实现只会被假定为总是返回独立实例。
默认实现返回true,通常认为FactoryBean管理一个单例的实例对象。
【2】BeanFactory
BeanFactory接口定义了IOC容器最基本的形式
,并且提供了IOC容器所应该遵守的最基本的服务契约。
BeanFactory接口设计了getBean方法,这个方法是使用IOC容器API的主要方法,通过这个方法,可以取得IOC容器中管理的Bean,Bean的取得是通过指定名字来索引的。如果需要在获取Bean时对Bean的类型进行检查,BeanFactory接口定义了带有参数的getBean方法,这个方法的使用与不带参数的getBean方法类似,不同的是增加了对Bean检索的类型的要求。
在Spring中,实际上是把DefaultListableBeanFactory
作为一个默认的功能完整的IOC容器来使用的。
有了BeanFactory的定义,用户可以执行以下操作:
- 通过接口方法
containsBean
让用户能够判断容器是否含有指定名字的Bean; - 通过接口方法
isSingleton
来查询指定名字的Bean是否是Singleton类型的Bean。对于Singleton属性,用户可以在BeanDefinition中指定; - 通过接口方法
isPrototype
来查询指定名字的Bean是否是prototype类型的。与Singleton属性一样,这个属性也可以由用户在BeanDefinition中指定; - 通过接口方法
isTypeMatch
来查询指定了名字的Bean的Class类型是否是特定的Class类型。这个Class类型可以由用户来指定。 - 通过接口方法
getType
来查询指定名字的Bean的Class类型; - 通过接口方法
getAliases
来查询指定了名字的Bean的所有别名,这些别名都是用户在BeanDefinition中定义的。
BeanFactory接口源码
public interface BeanFactory {
//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
//如果需要得到工厂本身,需要转义
String FACTORY_BEAN_PREFIX = "&";
//根据bean的名字,获取在IOC容器中得到bean实例
Object getBean(String var1) throws BeansException;
//根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
//提供对bean的检索,看看是否在IOC容器有这个名字的bean
boolean containsBean(String var1);
//根据bean名字得到bean实例,并同时判断这个bean是不是单例
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
//得到bean实例的Class类型
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String var1);
}
可以看到,这里定义的只是一系列的接口方法,通过这一系列的BeanFactory接口,可以使用不同的Bean的检索方法,很方便地从IOC容器中得到需要的Bean,从而忽略具体的IOC容器的实现。
其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范BeanFactory 有三个子类:ListableBeanFactory
、HierarchicalBeanFactory
和AutowireCapableBeanFactory
。
但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory
,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如
- ListableBeanFactory 接口表示这些 Bean 是可列表的,
- 而 HierarchicalBeanFactory 表示的是这些Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。
- AutowireCapableBeanFactory 接口定义Bean 的自动装配规则。
这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。
在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。
而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition(XML文件中对bean的描述)。