Spring中BeanFactory和FactoryBean详解

在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 有三个子类:ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactory

但是从上图中我们可以发现最终的默认实现类是 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的描述)。

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值