note:本文基于 spring-framework 5.2.2.RELEASE
What is the real Spring IoC container? BeanFactory
or ApplicationContext
?
官网描述
从 Spring 官网 beans-introduction 描述中可以得到以下信息:
- 源码工程中的
org.springframework.beans
和org.springframework.context
包是 Spring Framework 的 IoC container 基础BeanFactory
接口提供了一种高级配置机制能够管理任何类型的对象ApplicationContext
是BeanFactory
的一个子类,它增加了以下功能:
- 更容易和 Spring AOP 集成
- 消息资源处理(用于国际化)
- 事件发布
- 应用层面特定上下文,例如用于 web 应用的
WebApplicationContext
- 简而言之,
BeanFactory
提供了配置框架和基础的功能,而ApplicationContext
增加了更多企业级特性的功能。ApplicationContext
是BeanFactory
的一个完整超集
BeanFactory
or ApplicationContext
?
BeanFactory
和 ApplicationContext
应该如何选择?
Spring 官网 BeanFactory or ApplicationContext 中也做了详细的描述。重点是这两句:
You should use an ApplicationContext unless you have a good reason for not doing so
(你应该使用 ApplicationContext,除非你有很好的理由不使用它)
Because an ApplicationContext includes all the functionality of a BeanFactory, it is generally recommended over a plain BeanFactory
(因为 ApplicationContext 包含了 BeanFactory 的所有功能,通常建议使用)
还附了一张关于 Feature Matrix(功能矩阵) 的表来描述 BeanFactory
和 ApplicationContext
接口和实现所提供的功能:
特性 | BeanFactory | ApplicationContext |
---|---|---|
Bean 实例化/加工(wiring) | Yes | Yes |
集成生命周期管理 | No | Yes |
自动注册 BeanPostProcessor |
No | Yes |
自动注册 BeanFactoryPostProcessor |
No | Yes |
方便 MessageSource 访问(用于国际化) |
No | Yes |
内置 ApplicationEvent 发布机制 |
No | Yes |
可以看出,官方更推荐使用 ApplicationContext
,但这并不代表 BeanFactory
就没有使用场景,只是场景真的比较有限,具体可参考官方文档描述。
实现原理
ApplicationContext Java Diagrams
从图中可以可以反映出:ApplicationContext
自身就是一个 BeanFactory
并且它还拥有其他功能。
那么,ApplicationContext
是 BeanFactory
的一个完整超集这是如何实现的呢?
ApplicationContext internal BeanFactory
ApplicationContext
源码中,getAutowireCapableBeanFactory() 方法注释中有个重要的字眼:internal BeanFactory。
这个字眼是否意味着,虽然 ApplicationContext
是一个 BeanFactory
,但是其内部还有一个 BeanFactory?如果真是这样,是否多此一举呢?
顺着该方法注释提示去 @see ConfigurableApplicationContext#getBeanFactory() 源码,发现该方法注释第一句就解答了疑问:
Return the internal bean factory of this application context. Can be used to access specific functionality of the underlying factory.
(返回此应用程序上下文的内部 bean factory。可用于访问基础 factory 的特定功能)
How to set internal BeanFactory
这里就有一个新问题,这个 internal BeanFactory 是如何设置进去的?
按常理来讲,既然有 getBeanFactory() 方法,那应该也有一个 setBeanFactory() 方法用来把 beanFactory set 进去,但是很遗憾,源码中并没有 setBeanFactory() 方法。
继续查看 getBeanFactory() 的实现,发现有两个类实现了该方法:AbstractRefreshableApplicationContext
和 GenericApplicationContext
。
继续看这两个类的源码会发现,这两个类里都有一个非常重要的内部属性:DefaultListableBeanFactory beanFactory,而 getBeanFactory() 方法返回的 internal BeanFactory 正是这个 beanFactory!
这种方式有点像代理,通过组合的方式把 BeanFactory
的实现 DefaultListableBeanFactory
组合进来,并不是完全去抽象或继承该类。
题外:其实这两个类都很重要,Spring 中”著名”的两个类都继承自它们:
ClassPathXmlApplicationContext
extends … extendsAbstractRefreshableApplicationContext
AnnotationConfigApplicationContext
extendsGenericApplicationContext
应用 internal BeanFactory
可以看下 Spring 里 AbstractApplicationContext
里的各个 getBean() 方法的实现,都是先调用 getBeanFactory() 再调用 getBean():
1 |
|
可以看出,ApplicationContext
其实并不具备依赖查找的能力,都是委托给自己的 internal beanFactory 来实现。
同时也反映了,BeanFactory
其实是最底层的 IoC 容器,ApplicationContext
是在 BeanFactory
的基础上增加了一些特性。
Summary
综上,可以说,BeanFactory
含有的能力 ApplicationContext
都有,并且 ApplicationContext
提供了更多的特性。
再看官网这句话,就豁然开朗了: BeanFactory
提供了配置框架和基础的功能,而 ApplicationContext
增加了更多企业级特性的功能。ApplicationContext
是 BeanFactory
的一个完整超集。