关于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
在FactoryBean的注释中有这么一段话,如下:
实现了BeanFactory接口的这些对象就是各个对象的工厂,这些工厂被容器用于获取各个Bean实例,而不是IOC容器直接获取各个Bean实例;
FactoryBean并不直接创建对象,而是将创建对象的工作委托给其getObject方法返回的对象,即FactoryBean注册的只是FactoryBean的实现类,在使用FactoryBean时,Spring会先将FactoryBean的实现类加载并初始化,然后在需要使用对象的时候,调用FactoryBean的getObject方法获取对象实例;
注:IOC容器只负责管理FactoryBean实例的生命周期,而不负责FactoryBean创建的对象的生命周期,即FactoryBean实例是由IOC容器创建,而FacotyBean实例管理的对象,由FactoryBean实例创建;
- getObject
返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器的单实例缓存池中;
- isSingleton
返回由FactoryBean创建的Bean实例的作用域是singleton,还是prototype,即单例还是非单例,这里有两种处理方式:
-
- 单例FactoryBean生成的bean实例也认为是单例类型,需放入缓存中,供后续重复使用;
- 非单例FactoryBean生成的bean实例则不会被放入缓存中,每次都会创建新的实例;
- getObjectType
返回FactoryBean创建的bean类型;
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创建对象是非标的创建流程,它可以允许
参考:[https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-beanfactory]