Loading

关于Spring中的ApplicationContext,BeanFactory,FactoryBean对比

  • BeanFactory

BeanFactory是Bean的工厂,Spring的顶层核心接口,它为Spring的IoC功能提供了基础,它使用了简单工厂,负责生产Bean,Bean的定义信息

 

BeanFactory的类图

 

  • ApplicationContext

从上面的类图可以看出ApplicationContext包含了BeanFactory的所有功能,ApplicationContext更值得推荐,除了一些特定的场景,例如在资源受限的设备上运行的内嵌的应用;

使用GenericApplicationContext及其子类AnnotationConfigApplicationContext作为自定义引导的常见实现, 这些是Spring用于所有常见目的的核心容器的主要入口点:加载配置文件,触发类路径扫描,以编程方式注册bean定义和带注解的类,以及(从5.0开始)注册功能bean定义;

从使用角度上说,ApplicationContext是面向用户的,它不仅能提供Bean和调用工厂生产Bean,还能提供一系列的服务(如国际化,加载Bean定义,监听器等);在ApplicationContext(例如GenericApplicationContext实现)中,按照约定(即通过bean名称或bean类型,特别是后处理器)检测到几种bean, 而普通的DefaultListableBeanFactory对任何特殊bean都是不可知的;

 

BeanFactory与ApplicationContext功能对比  

Feature BeanFactory ApplicationContext
Bean Bean实例化/装配 Yes Yes
集成的生命周期管理BeanPostProcessor No Yes
自动注册BeanPostProcessor No Yes
自动注册BeanFactoryPostProcessor No Yes
便利的MessageSource访问 (国际化) No Yes
内置ApplicationEvent发布机制 No Yes

 

  • FactoryBean

BeanFactory和FactoryBean都是用于创建对象,一般情况下,Spring通过反射机制利用Bean的Class属性指定实现类来实例化Bean,由BeanFactory引导Bean的创建流程;在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在<bean>@Bean 中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案;Spring为此提供了一个org.springframework.beans.factory.FactoryBean的工厂类接口,用户可以通过实现该接口来定制实例化Bean的逻辑

 

在FactoryBean的注释中有这么一段话,如下:

实现了BeanFactory接口的这些对象就是各个对象的工厂,这些工厂被容器用于获取各个Bean实例,而不是IOC容器直接获取各个Bean实例;

FactoryBean并不直接创建对象,而是将创建对象的工作委托给其getObject方法返回的对象,即FactoryBean注册的只是FactoryBean的实现类,在使用FactoryBean时,Spring会先将FactoryBean的实现类加载并初始化,然后在需要使用对象的时候,调用FactoryBean的getObject方法获取对象实例;

 

FactoryBean作为自定义的工厂对象的组件,可通过getObjcet方法把需要的Bean实例注入到容器中;

注:IOC容器只负责管理FactoryBean实例的生命周期,而不负责FactoryBean创建的对象的生命周期,即FactoryBean实例是由IOC容器创建,而FacotyBean实例管理的对象,由FactoryBean实例创建;

 

FactoryBean接口描述

  • getObject

返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器的单实例缓存池中;

  • isSingleton

返回由FactoryBean创建的Bean实例的作用域是singleton,还是prototype,即单例还是非单例,这里有两种处理方式:

    • 单例FactoryBean生成的bean实例也认为是单例类型,需放入缓存中,供后续重复使用;
    • 非单例FactoryBean生成的bean实例则不会被放入缓存中,每次都会创建新的实例;
  • getObjectType

返回FactoryBean创建的bean类型;

 

当容器启动完成,FactoryBean托管的Bean实例是没有创建的,只会创建FactoryBean实现类的的实例,如果需要获取FactoryBean托管的Bean实例本身,当调用getBean需要在id前加个&

 

FactoryBean实例化Bean的流程

需要注意的是,FactoryBean#getObject创建的对象是缓存到factoryBeanObjectCache中,而FactoryBean的实现类会被缓存到singletonObjects中,即Spring的一级缓存;

FactoryBeanRegistrySupport#getObjectFromFactoryBean

 

FactoryBean测试

查看代码
 @Test
public void mainTest13() {
    AnnotationConfigApplicationContext context =   new AnnotationConfigApplicationContext(
            MainConfig10.  class );

    System.out.println(  "IOC容器创建完成..." );

    // 调用FactoryBean#getBean方法,入参为Bean id,得到的对象为FactoryBean#getObjectType的对象
    // FactoryBean要获取工厂Bean本身,需要在id前加个&
    // org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance
    Object factoryBean1 = context.getBean(  "demoFactoryBean" );
    Object factoryBean2 = context.getBean(  "demoFactoryBean" );
    System.out.println(  "factoryBean1==factoryBean2 :" + (factoryBean1 == factoryBean2));
    System.out.println(  "bean的类型:" + factoryBean1.getClass());

    Object factoryBean3 = context.getBean(  "&demoFactoryBean" );
    System.out.println(  "bean的类型:" + factoryBean3.getClass());
}

  

查看代码
 @Configuration
public class MainConfig10 {
    @Bean
    public DemoFactoryBean demoFactoryBean() {
        return new DemoFactoryBean();
    }
}

  

查看代码
 public class DemoFactoryBean implements FactoryBean {

    /**
     * 是否单例进行控制
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true ;
    }

    /**
     * 返回对象,把对象放到容器中
     * @return
     * @throws Exception
     */
    @Override
    public Person getObject()   throws Exception {
        return new Person();
    }

    /**
     * 返回对象类型
     * @return
     */
    @Override
    public Class<!--?--> getObjectType() {
        return Person.  class ;
    }
}

  

执行结果如下:

BeanFactory与FactoryBean区别

BeanFactory和FactoryBean都可以创建对象,但是它们的创建流程方式是不同的;

当使用BeanFactory创建对象时,这是一个标准的创建流程,必须遵循Bean的生命周期,经过一系列的流水线式的流程创建;而FactoryBean创建对象是非标的创建流程,它可以允许用户可以通过实现该接口来定制实例化Bean的逻辑,定制化创建方式可以是通过代理生成或者new创建,即实现对应的getObject方法,返回的是需要创建的对象实例,该对象的实例可以是通过代理生成的,也可以是直接new创建的;

 

参考:[https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-beanfactory]

 

posted @ 2021-08-24 09:34  街头卖艺的肖邦  阅读(285)  评论(0编辑  收藏  举报