Spring扩展——BeanFactory和FactoryBean

BeanFactory和FactoryBean

BeanFactory和FactoryBean长得很相似,也很容易让我们产生误解,特别是对于初学者而言,搞懂他俩关系非常有必要,因为这两个接口,是Spring框架中非常重要的两个接口,也是很多同鞋在面试中经常被问到的问题

BeanFactory(bean工厂)

BeanFactory是Spring IOC容器中最基本的容器接口,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范,这当然也是Spring框架提供给我们日常开发最重要的一点,Spring框架通过BeanFactory来管理整个bean对象的生命周期,包括bean对象的实例化、初始化、销毁等等过程,也很好的为我们解决了Bean对象之间的相互依赖关系,提供多种属性注入的配置方式。

在Spring中还有一个非常重要的接口,ApplicationContext,Spring用它管理整个上下文,而通过阅读源码我们发现,在Spring中的ApplicationContext接口的具体实现类里面,有一个成员变量BeanFactory,我们通过ApplicationContext.getBean的方式来获取的bean对象的时候,实际上是把它交给了BeanFactory来间接获取的。

实际上我们可以这么理解,Spring通过BeanFactory来为我们管理Bean对象的生命周期,而Spring的ApplicationContext为我们的容器提供一个可靠的运行环境。
所以Spring的容器启动,可以简单地分为以下几个步骤

  1. ApplicationContext环境的准备;
  2. Bean容器的准备;
  3. 通过配置文件获取bean对象的定义信息;
  4. 将Bean定义信息注册到Bean容器中,也就是我们说的BeanFactory;
  5. 由BeanFactory创建bean对象,并管理bean对象(实例化、初始化、依赖注入等);

当然这中间还有许多的操作。
上面我们说过BeanFactory为我们的bean容器提供了管理Bean对象时最基本的规范,包括bean对象的实例化、初始化、属性注入、后置处理、销毁等等操作。在我们通过ApplicationContext.getBean方法获取bean对象的时候,我们发现实际它是交由BeanFactory来获取的。

实际上,为了加快getBean方法获取bean的速度,BeanFactory的实现类里面为我们提供了多种缓存。比如对于我们单例bean对象,在第一次创建成功后,就会将它放入BeanFactory的Map缓存里面,以便于后期再获取的时候,能够保证获取到的是同一对象,也就保证了bean的单例性。

FactoryBean(工厂bean)

FactoryBean接口,顾名思义工厂Bean,只看名字,我们就知道,它是用来描述bean类型,XXXBean,表示这是一个XXX类型的Bean。
所以我们可以猜出两点来

  1. 它肯定自身也是一个Bean对象
  2. 根据XXXBean理论得出,它应该是一个具有XXX功能或属性的Bean,这里XXX是Factory,所以它应该是一个具有创建其它Bean功能的一个Bean对象
public interface FactoryBean<T> {
    /**
     * 根据泛型返回一个此泛型的具体对象
     *
     * @return
     * @throws Exception
     */
    T getObject() throws Exception;
	/**
	 * 获取Class类型
	 * @return
	 */
	Class<?> getObjectType();
	/**
	 * 是否是单例
	 * @return
	 */
    default boolean isSingleton() {
        return true;
    }
}

根据上面猜出的结论,我们大致可以得出,只要实现了这个接口对象,它本身也应该是一个bean,应该交由Spring容器进行管理
在FactoryBean接口里面提供了3个方法,3个方法的用途请看代码里的注释
测试代码来一波

1.定义一个实现了FactoryBean接口的bean对象,通过注解的方式,name是teacherBeanFactory

@Component(value = "teacherBeanFactory")
public class Teacher implements FactoryBean<Student> {
    @Override
    public Student getObject() throws Exception {
        return new Student("yan");
    }
    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }

    /**
     * 是否是单例,返回true
     *
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

2.Student类,没有标注任何注解

public class Student {
    private String name;
    public Student(String name) {
        this.name = name;
    }
}

2.通过注解的方式new一个ApplicationContext

    public static void main(String[] args) {
        //通过注解的方式启动一个Spring上下文
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Teacher.class);
        String[] beanDefinitionNames = applicationContext.getBeanFactory().getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("name: "+beanDefinitionName + " bean: " + applicationContext.getBean(beanDefinitionName));
        }
        Teacher bean = applicationContext.getBean(Teacher.class);
        System.out.println(bean);
    }

3.打印输出(还有一些spring内部的bean没有写到这里)

name: teacherBeanFactory bean:com.mashibing.ycb.factorybean.Student@1963006a
com.mashibing.ycb.factorybean.Teacher@7fbe847c

我们可以看到,在Spring容器里面肯定存在两个不同的对象:1.Student 2.Teacher
for循环里面通过bean名称(teacherBeanFactory)获取到的bean居然是Student对象,很神奇吧。
正好印证了我们上面的猜测,FactoryBean不是一个简单的bean,它是一个可以创建其它bean的bean。
通过debug,我们发现在我们的BeanFactory的单例缓存(一级缓存)中,存在着Teacher类型的bean,名称就是我们刚刚在Teacher类上定义的名称——@Component(value = "teacherBeanFactory")
而在测试的时候,跟我们预期不一样的是,通过applicationContext.getBean("teacherBeanFactory")的时候,获取得到居然是一个Student的Bean对象。
其实在getBean的时候,有以下流程

可以看到Student对象的bean实际上是存放在factoryBeanObjectCache中的,并不是存放在SingletonMap(一级缓存)里的

结论

BeanFactory:BeanFactory顾名思义,它是一个工厂,一个bean工厂,描述的是一个工厂,而不是一个bean。它是负责生产和管理bean的一个工厂(很大的工厂,里面有很多的bean)。它是IOC容器最底层的接口,提供了对bean管理的基本规范。

FactoryBean:言而之,它是一个bean,一个带有创建功能的bean,描述的是一个bean,工厂只是它的一个修饰符,提供了一个创建bean的一个渠道,只是提供了一个渠道。

我们通俗点表达
机械厂——————生产很多种机械设备(包括数控机床)(BeanFactory)
数控机床——————生产特殊机械设备(FactoryBean)

如果有写得不准确的地方,请读者大胆在评论区指出

posted @ 2021-04-01 23:20  心若向阳花自开  阅读(394)  评论(0编辑  收藏  举报