在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应用到BeanFactoryjava// 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应用到BeanFactoryjava// 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。