全方位解析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。

相关推荐
打工仔折腾 AI6 小时前
从 Demo 到生产级 Agent:8 个关键设计机制与 Python 实现拆解
java·jvm·人工智能·后端·python·langchain·ai agent 实战
殷色玫瑰7 小时前
C/C++ 内存管理详解:从内存分布到 new/delete 底层原理
java·linux·c语言·c++
青山木8 小时前
Hot 100 --- 编辑距离
java·数据结构·算法·leetcode·动态规划
朝朝辞暮i8 小时前
C++ 第 26 课:对象、指针与 ->
java·开发语言·c++
长弓三石8 小时前
把 AgentScope Harness 装进 RuoYi-Vue-Plus:纯 Java AI 平台的集成实践
java·人工智能·agent
蜗牛互联网9 小时前
MongoDB Atlas Agent Engine之后,如何用版本门禁防止陈旧写入
java·数据库·人工智能·后端·mongodb
长弓三石9 小时前
企业级智能体的权限到底怎么落地?以 BizBuddy 为例
java·人工智能·agent
用户4270276726819 小时前
一次缓存优化:SQL 从 502 降到 5
java
小师兄吃牛肉9 小时前
C语言指针进阶全解析
java·c语言·算法
Joy T9 小时前
聊天系统中五大ID的演进与实战解析
java·前端·人工智能·spring·agent入门