FactoryBean、ObjectFactory和BeanFactory的区别

BeanFactory、FactoryBean和ObjectFactory

  • BeanFactory就是对象工厂,用于实例化和保存对象。
  • FactoryBean是一个工厂对象,用于实例化创建过程比较复杂的对象。
  • ObjectFactory是某个特定的工厂,用于在项目启动时,延迟实例化对象,解决循环依赖问题。

BeanFactory

是一个接口,public interface BeanFactory,提供如下方法:

  • Object getBean(String name)
  • <T> T getBean(String name, Class<T> requiredType)
  • <T> T getBean(Class<T> requiredType)
  • Object getBean(String name, Object... args)
  • boolean containsBean(String name)
  • boolean isSingleton(String name)
  • boolean isPrototype(String name)
  • boolean isTypeMatch(String name, Class<?> targetType)
  • Class<?> getType(String name)
  • String[] getAliases(String name)

在 Spring 中,BeanFactory是 IoC 容器的核心接口。它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

BeanFactory 提供的高级配置机制,使得管理任何性质的对象成为可能。
ApplicationContextBeanFactory 的扩展,功能得到了进一步增强,比如更易与 Spring AOP 集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的 context 实现(如针对 web 应用的WebApplicationContext)。

用的比较多的 BeanFactory 的子类是 ClassPathXmlApplicationContext,这是 ApplicationContext接口的一个子类,ClassPathXmlApplicationContext从 xml 的配置文件中获取 bean 并且管理他们,例如:

public static void main(String[] args) throws Exception {
    BeanFactory bf = new ClassPathXmlApplicationContext("student.xml");
    Student studentBean = (Student) bf.getBean("studentBean");
    studentBean.print();
}

XML配置如下:

<bean id="studentBean" class="advanced.Student">
    <property name="name" value="Tom"/>
    <property name="age" value="18"/>
</bean>

FactoryBean

Spring 中为我们提供了两种类型的 bean,一种就是普通的 bean,我们通过 getBean(id) 方法获得是该 bean 的实际类型,另外还有一种 bean 是 FactoryBean,也就是工厂 bean,我们通过 getBean(id) 获得是该工厂所产生的 Bean 的实例,而不是该 FactoryBean 的实例。

FactoryBean 从名字上能看出这是一个Bean。Bean就是Spring对对象的一种定义,一个Bean就是一个或者一些同类型的对象。
FactoryBean是一个接口。

实现了 FactoryBean 接口的类有能力改变 bean,FactoryBean 希望你实现了它之后返回一些内容,Spring 会按照这些内容去注册 bean。
public interface FactoryBean<T>,提供如下方法:

public interface FactoryBean<T> {

    //返回的对象实例
    T getObject() throws Exception;
    //Bean的类型
    Class<?> getObjectType();
    //true是单例,false是非单例  在Spring5.0中此方法利用了JDK1.8的新特性变成了default方法,返回true
    boolean isSingleton();
}

getObject用来返回实例化后的对象。
getObjectType用来返回对象的类型。
isSingleton用来标识对象是否为单例的,这里默认为true,Spring会将实例化后的对象放入BeanFactory容器中。

通常情况下,bean 无须自己实现工厂模式,Spring 容器担任工厂 角色;但少数情况下,容器中的 bean 本身就是工厂,作用是产生其他 bean 实例。由工厂 bean 产生的其他 bean 实例,不再由 Spring 容器产生,因此与普通 bean 的配置不同,不再需要提供 class 元素。

凡是实现了FactoryBean接口的类,负责返回这个java类的实例化对象。
从设计模式的角度来看这就是典型的工厂方法模式。由一个特定的工厂来生产特定的java类的实例化对象。

那么这种写法有哪些好处呢?
正常情况下,Spring中在实例化对象的时候,都是由BeanFactory从上下文中获取BeanDefinition信息,然后通过反射,调用这个java类的构造方法进行实例化。而现在这种形式,我们相当于将实例化的功能交给了FactoryBean去实现。这种方式主要使用在一些比较复杂的实例化过程中,并非简单地设置一些参数或者设置的参数过多,过程中可能需要做一些复杂的解析、判断和逻辑处理,这个时候交由Spring去通过反射进行实例化可能就不太灵活了,

Spring容器中有两种Bean,一种是普通的Bean对象,一种是实现了FactoryBean的工厂Bean对象。如果从BeanFactory中getBean的时候,获取到的Bean对象是工厂Bean,会自动的调用它的getObject方法返回真实实例化对象。
如果就是需要获取FactoryBean对象,需要在getBean的时候加上前缀’&’。

Spring自身就对FactoryBean有70多种实现,比较常见的就是Proxy,Jndi等场景。AOP中使用的ProxyFactoryBean。
Dubbo中使用的ReferenceBean。
Mybatis中使用的SqlSessionFactoryBean。

示例:
构造一个 FactoryBean 的实现:

public class StudentFactoryBean implements FactoryBean<Student> {
    private String name;
    private int age;
    @Override
    public Student getObject() throws Exception {
        return new Student(name, age);
    }
    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }
    /**
     * 工厂所管理的对象是否为单例的
     * 即如果该方法返回true,那么通过getObject()方法返回的对象都是同一个对象
     */
    @Override
    public boolean isSingleton() {
        return true;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

XML配置如下:

<bean id="studentFactoryBean" class="spring.StudentFactoryBean">
    <property name="name" value="Tom"/>
    <property name="age" value="28"/>
</bean>

使用:

public static void main(String[] args) throws Exception {
    BeanFactory bf = new ClassPathXmlApplicationContext("student.xml");
    Student studentBean = (Student) bf.getBean("studentFactoryBean");

    studentBean.print();
}

ObjectFactory

public interface ObjectFactory<T> {

    //返回的对象实例
    T getObject() throws BeansException;
}

这用于延迟查找的场景,它就是一个普通工厂,当得到 ObjectFactory 对象时,相当于 Bean 没有被创建,只有当 getObject() 方法时,才会触发 Bean 实例化等生命周期。
主要用于暂时性地获取某个 Bean Holder 对象,如果过早的加载,可能会引起一些意外的情况,比如当 Bean A 依赖 Bean B 时,如果过早地初始化 A,那么 B 里面的状态可能是中间状态,这时候使用 A 容易导致一些错误。

引用:
https://www.jianshu.com/p/05c909c9beb0

https://www.jianshu.com/p/a2807797fed0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值