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

在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。

相关推荐
captain3763 小时前
MyBatis(入门5)其他查询操作
java·数据库·spring boot·mybatis
Novproxy_Z4 小时前
商用代理避坑:如何识别商家拿机房 IP 冒充住宅 IP
java·网络·tcp/ip
文丑颜不良啊4 小时前
LeetCode1481~1500题目解析
java·leetcode
2601_962885724 小时前
quotes 字段全解:涨跌幅、振幅、换手率的口径与单位
java·前端·spring
前端精髓5 小时前
调用openrouter的免费API模型
java·前端·javascript
步行cgn5 小时前
Spring MVC 拦截器 Interceptor 详解:从执行流程到实战应用
java·spring·mvc
文丑颜不良啊5 小时前
LeetCode1381~1400题目解析
java·leetcode
开开心心_Every5 小时前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea
萧瑟余晖6 小时前
Spring Batch核心模型与快速上手详解
java·spring·batch
缓慢更新7 小时前
AI 辅助生成单测:从接口定义到用例的流水线
java·服务器·前端·网络·数据库·人工智能