全方位解析Spring IoC:(二)容器

Spring中,IoC容器主要负责对bean进行实例化、配置和组装,其中对于这些bean需要我们通过XMLJava代码等方式声明在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配置的格式作任何限制,即对于存储的配置格式是LDAPRDBMS还是XML都没有任何限制。所有这些不同格式的配置,容器都是通过扩展类(例如XmlBeanDefinitionReaderAutowiredAnnotationBeanPostProcessor等)进行解析,并存储为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

实际上,ApplicationContextbean相关的能力都源自于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

虽说ApplicationContextBeanFactory都能完成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

BeanFactoryPostProcessorBeanPostProcessor对于许多容器的功能特性是必不可少的,例如注解处理和AOP代理等功能都是通过它来实现的。

最后,这里列出了BeanFactoryApplicationContext提供功能的对比:

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

相关推荐
24k小善1 小时前
Flink TaskManager详解
java·大数据·flink·云计算
想不明白的过度思考者1 小时前
Java从入门到“放弃”(精通)之旅——JavaSE终篇(异常)
java·开发语言
.生产的驴1 小时前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
猿周LV1 小时前
JMeter 安装及使用 [软件测试工具]
java·测试工具·jmeter·单元测试·压力测试
晨集1 小时前
Uni-App 多端电子合同开源项目介绍
java·spring boot·uni-app·电子合同
时间之城1 小时前
笔记:记一次使用EasyExcel重写convertToExcelData方法无法读取@ExcelDictFormat注解的问题(已解决)
java·spring boot·笔记·spring·excel
椰羊~王小美2 小时前
LeetCode -- Flora -- edit 2025-04-25
java·开发语言
凯酱2 小时前
MyBatis-Plus分页插件的使用
java·tomcat·mybatis
程序员总部2 小时前
如何在IDEA中高效使用Test注解进行单元测试?
java·单元测试·intellij-idea
oioihoii2 小时前
C++23中if consteval / if not consteval (P1938R3) 详解
java·数据库·c++23