在Spring
中,IoC
容器主要负责对bean
进行实例化、配置和组装,其中对于这些bean
需要我们通过XML
或Java
代码等方式声明在Metadata
配置中以让容器进行读取并获得指导。
在
Spring
中,IoC
容器所管理的对象称之为bean
,它是由IoC
容器实例化、组装和管理的对象。
下图从宏观视角来给出Spring
是如何工作的。
text
+
|
| Your Business Objects(POJOs)
|
v
+----------+-----------+
| |
+----------------->+ The Spring Container |
Configuration | |
Metadata +----------+-----------+
|
| produces
|
v
+-----------+-------------+
| |
| Fully configured system |
| Ready for Use |
| |
+-------------------------+
从上图中显示,在IoC
容器中通过结合业务对象类和Metadata
配置来创建和初始化容器类(例如,ApplicationContext
),以此来得到一个配置完全并可执行的系统或应用。
需要注意,容器本身并不会对
Metadata
配置的格式作任何限制,即对于存储的配置格式是LDAP
、RDBMS
还是XML
都没有任何限制。所有这些不同格式的配置,容器都是通过扩展类(例如XmlBeanDefinitionReader
、AutowiredAnnotationBeanPostProcessor
等)进行解析,并存储为BeanDefinition
来进行处理,这也大幅增加了容器的灵活性和可扩展性。
ApplicationContext
Spring
使用了ApplicationContext
表示IoC
容器,它会读取Metadata
配置中的指令对bean
进行实例化、配置和组装。因此,在将业务对象类和Metadata
配置注入到容器ApplicationContext
后,我们就可以使用它来获取对应的bean
实例,例如:
java
// create and configure beans
ApplicationContext context = ...;
// retrieve configured instance
IocService service = context.getBean("iocService", IocService.class);
在开发过程中一个比较好的做法是通过依赖注入的方式来配置应用实例。换句话说,我们应该通过容器
Push
配置到相应的地方;而不是主动从容器中Pull
相应的配置,比如主动通过ApplicationContext
来获取对象(以任何形式)。
BeanFactory
实际上,ApplicationContext
中bean
相关的能力都源自于BeanFactory
(继承自BeanFactory
),所以我们也能通过BeanFactory
完成bean
的实例化、配置和组装。即:
java
// create and configure beans
BeanFactory factory = ...;
// retrieve configured instance
IocService service = factory.getBean("iocService", IocService.class);
本质上,BeanFactory
相当于是应用组件的注册中心,持有并集中了大量的应用组件的配置信息(例如,持有大量的bean
定义,每个bean
定义都具有独一无二的名字)。当然,我们也可以将BeanFactory
看作是IoC
容器的"客户端",通过这个"客户端"我们可以完成会IoC
容器访问。
ApplicationContext
vs. BeanFactory
虽说ApplicationContext
与BeanFactory
都能完成bean
的实例化、配置和组装,但是我们一般更加推荐使用ApplicationContext
。因为ApplicationContext
不但包含了BeanFactory
所有的能力,而且它还会将几种特殊的bean
(特别是后置处理器BeanPostProcessor
)加入到容器中激活Spring
的一些特性(例如,注解的处理或者AOP
代理的处理)。
当然,如果想在bean
的处理流程上得到完全的控制,我们也可以直接使用BeanFactory
。对于这种情况,默认是不会有上述ApplicationContext
的特性,而如果要加入这些特性则需要额外将这些特殊的bean
配置进BeanFactory
,例如:
-
将特殊的
BeanPostProcessor
应用到BeanFactory
java// BeanFactory的默认实现 DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // populate the factory with bean definitions XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(new FileSystemResource("beans.xml")); // now register any needed BeanPostProcessor instances factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor()); // now start using the factory
-
将特殊的
BeanFactoryPostProcessor
应用到BeanFactory
java// BeanFactory的默认实现 DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // populate the factory with bean definitions XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(new FileSystemResource("beans.xml")); // bring in some property values from a Properties file // PropertySourcesPlaceholderConfigurer属于BeanFactoryPostProcessor的一种实现 PropertySourcesPlaceholderConfigurer cfg = new PropertySourcesPlaceholderConfigurer(); cfg.setLocation(new FileSystemResource("jdbc.properties")); // now actually do the replacement cfg.postProcessBeanFactory(factory);
不难看出,将特殊的bean
逐个注册到BeanFactory
中是一件十分烦杂的事情,所以这就是为什么Spring
更加推荐使用ApplicationContext
。
BeanFactoryPostProcessor
和BeanPostProcessor
对于许多容器的功能特性是必不可少的,例如注解处理和AOP
代理等功能都是通过它来实现的。
最后,这里列出了BeanFactory
和ApplicationContext
提供功能的对比:
Feature |
BeanFactory |
ApplicationContext |
---|---|---|
Bean instantiation/wiring |
Yes |
Yes |
Integrated lifecycle management |
No |
Yes |
Automatic BeanPostProcessor registration |
No |
Yes |
Automatic BeanFactoryPostProcessor registration |
No |
Yes |
Convenient MessageSource access (for internationalization) |
No |
Yes |
Built-in ApplicationEvent publication mechanism |
No |
Yes |
Spring
官方推荐: 除非有特别充分的理由,否则推荐使用ApplicationContext
。