抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

BeanFactory与FactoryBean的区别

BeanFactory是Spring容器的顶级接⼝,给具体的IOC容器的实现提供了规范。

FactoryBean也是接⼝,为IOC容器中Bean的实现提供了更加灵活的⽅式,FactoryBean在IOC容器的基础上给Bean的实现加上了⼀个简单⼯⼚模式装饰模式,可以在getObject()⽅法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类。

区别:BeanFactory是个Factory,也就是IOC容器或对象⼯⼚,是对IOC容器的规范,FactoryBean是特殊的Bean,一种Bean创建的方式,对Bean的一种扩展对于复杂Bean对象初始化创建使用其可封装对象的创建细节。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进⾏管理的。

BeanFactory

BeanFactory,以Factory结尾,表示它是⼀个⼯⼚类(接⼝), 它负责⽣产和管理bean的⼀个⼯⼚。在Spring中,BeanFactory是IOC容器的核⼼接⼝,它的职责包括:实例化、定位、配置应⽤程序中的对象及建⽴这些对象间的依赖。

BeanFactory只是个接⼝,并不是IOC容器的具体实现,而Spring容器给出了很多种实现,如DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等,其中XmlBeanFactory就是常⽤的⼀个,该实现将以XML⽅式描述组成应⽤的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并⽤它来构建⼀个完全可配置的系统或应⽤。

BeanFactoryApplicationContext就是spring框架的两个IOC容器,现在⼀般使⽤ApplicationContext,其不但包含了BeanFactory的作⽤,同时还进⾏更多的扩展。

BeanFactory是spring中⽐较原始的Factory。如XMLBeanFactory就是⼀种典型的BeanFactory。

原始的BeanFactory⽆法⽀持spring的许多插件,如AOP功能、Web应⽤等。ApplicationContext接⼝, 它由BeanFactory接⼝派⽣⽽来,包含BeanFactory的所有功能,通常建议比BeanFactory优先。

ApplicationContext以⼀种更向⾯向框架的⽅式⼯作以及对上下⽂进⾏分层和实现继承,ApplicationContext包还提供了以下的功能:

  • MessageSource, 提供国际化的消息访问
  • 资源访问,如URL和⽂件
  • 事件传播
  • 载⼊多个(有继承关系)上下⽂ ,使得每⼀个上下⽂都专注于⼀个特定的层次,⽐如应⽤的web层;

BeanFactory提供的⽅法及其简单,仅提供了六种⽅法供开发者使用:

  • boolean containsBean(String beanName) 判断⼯⼚中是否包含给定名称的bean定义,若有则返回true
  • Object getBean(String) 返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回⼀个共享实例,否则将返回⼀个新建的实例,如果没有找到指定bean,该⽅法可能会抛出异常
  • Object getBean(String, Class) 返回以给定名称注册的bean实例,并转换为给定class类型
  • Class getType(String name) 返回给定名称的bean的Class,如果没有找到指定的bean实例,则抛出NoSuchBeanDefinitionException异常
  • boolean isSingleton(String) 判断给定名称的bean定义是否为单例模式
  • String[] getAliases(String name) 返回给定bean名称的所有别名

主要的实现类

  • AbstractBeanFactory:抽象bean工厂,大部分的实现类都是继承它的
  • DefaultListableBeanFactory:Spring默认的工厂
  • XmlBeanFactory:解析XML配置的bean工厂类
  • AbstractXmlApplicationContext:抽象应用容器上下文
  • ClassPathXmlApplicationContext:XML解析上下文对象,开发者创建Bean对象用(早期用得多)
// ClassPathXmlApplicationContext 使用
AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");
LifeBean life = container.getBean("life_prototype", LifeBean.class);

FactoryBean

⼀般情况下,Spring通过反射机制利⽤<bean>的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程⽐较复杂,如果按照传统的⽅式,则需要在<bean>中提供⼤量的配置信息。配置⽅式的灵活性是受限的,这时采⽤编码的⽅式可能会得到⼀个简单的解决⽅案。

Spring为此提供了⼀个org.springframework.bean.factory.FactoryBean的⼯⼚类接⼝,⽤户可以通过实现该接⼝定制实例化Bean的逻辑。FactoryBean接⼝对于Spring框架来说占⽤重要的地位,Spring⾃身就提供了70多个FactoryBean的实现。它们隐藏了实例化⼀些复杂Bean的细节,给上层应⽤带来了便利。

从Spring3.0开始,FactoryBean开始⽀持泛型,即接⼝声明改为FactoryBean<T>的形式以Bean结尾,表示它是⼀个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接⼝的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,⽽不是FactoryBean本身,如果要获取FactoryBean对象,请在id前⾯加⼀个&符号来获取,像这样getBean(&BeanName)

例如⾃⼰实现⼀个FactoryBean,功能:⽤来代理⼀个对象,对该对象的所有⽅法做⼀个拦截,在调⽤前后都输出⼀⾏LOG,模仿ProxyFactoryBean的功能。

package org.springframework.beans.factory;
public interface FactoryBean<T> {
    T getObject() throws Exception;
    Class<?> getObjectType();
    boolean isSingleton();
}

该接口定义了以下3个方法:

  • T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中;
  • boolean isSingleton():返回由FactoryBean创建的Bean实例的作⽤域是singleton还是prototype;
  • Class<?> getObjectType():返回FactoryBean创建的Bean类型。

当配置⽂件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean()⽅法返回的不是FactoryBean本身,⽽是FactoryBean#getObject()⽅法所返回的对象,相当于FactoryBean#getObject()代理了getBean()⽅法。

常用类

  • ProxyFactoryBean:Aop代理Bean
  • GsonFactoryBean:Gson

使用案例

bean配置文件life.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- BeanFactory and FactoryBean -->
    <bean id="life" class="org.lgq.spring.LifeBean">
        <property name="name" value="lgq"/>
    </bean>
    <bean id="lifeFromFactory" class="org.lgq.spring.LifeFactoryBean">
        <property name="initStr" value="enhanced lgq"/>
    </bean>
</beans>

LifeBean代码

public class LifeBean {

    private String name;

    public LifeBean() {
        System.out.println("LifeBean构造函数");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("LifeBean{");
        sb.append("name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }

    public void init() {
        System.out.println("this is init of LifeBean:");
    }

    public void destroy() {
        System.out.println("this is destroy of LifeBean:" + this);
    }

}

LifeFactoryBean代码

public class LifeFactoryBean implements FactoryBean<LifeBean> {
    /**
     * 初始化str
     */
    private String initStr;

    public String getInitStr() {
        return initStr;
    }

    public void setInitStr(String initStr) {
        this.initStr = initStr;
    }

    @Override
    public LifeBean getObject() throws Exception {
        LifeBean lifeBean = new LifeBean();
        lifeBean.setName(initStr);
        // 这里可以对创建的bean做更多的操作
        return lifeBean;
    }

    @Override
    public Class<?> getObjectType() {
        return LifeBean.class;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("LifeFactoryBean{");
        sb.append("initStr='").append(initStr).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

测试代码

public class LifeTest {
    @Test
    public void testLife() {
        // BeanFactory
        BeanFactory container = new ClassPathXmlApplicationContext("life.xml");
        // 获取life对象
        LifeBean life = container.getBean("life", LifeBean.class);
        System.out.println(life);
        // 通过factoryBean获取
        LifeBean lifeFromFactory = container.getBean("lifeFromFactory", LifeBean.class);
        System.out.println(lifeFromFactory);
        // 获取lifeFactoryBean
        Object bean = container.getBean("&lifeFromFactory");
        System.out.println(bean instanceof LifeFactoryBean);
        LifeFactoryBean factoryBean = (LifeFactoryBean) bean;
        System.out.println("初始化字符串:" + factoryBean.getInitStr());
    }
}

输入结果

LifeBean{name='lgq'}
LifeBean{name='enhanced lgq'}
true
初始化字符串:enhanced lgq

总结

BeanFactory是个Factory,也就是IOC容器或对象⼯⼚,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进⾏管理的。但对FactoryBean⽽⾔,这个Bean不是简单的Bean,⽽是⼀个能⽣产或者修饰对象⽣成的⼯⼚Bean,它的实现与设计模式中的⼯⼚模式和修饰器模式类似。

评论