spring框架四个基础核心一(IOC容器)

1.引言

spring框架有四个基础核心:

  • IoC容器
  • JavaConfig
  • 事件监听
  • Spring factories

从本篇文章开始,我会依次给你分享关于四个基础核心的相关知识。开始吧!

2.IoC容器

2.1.什么是IOC容器

可以把spring IoC容器,看做一家餐馆,你到餐馆点菜,你只关心最终吃到这道菜,至于菜需要用什么原料?怎么做?你其实是不关心的。

同理,回到技术术语,当你在使用IoC容器的时候,你只关心需要什么bean对象,至于这个bean对象是怎么实例化的?依赖了什么组件?你其实是不关心的。

好了,那么到底什么是IoC呢?它的英文名称是Inversion of Control,即控制反转。控制反转有点抽象,我给你举个例子,你大概就懂了。

  • 在没有spring框架以前,程序代码中,当需要某个对象的时候,通常需要new 的方式来获取对象,并且通过构造方法,或者set方法处理对象之间的依赖关系。关键词:这里是写程序的人,在控制管理对象
  • 在有了spring框架后,程序代码中,当需要某个对象的时候,通常从ApplicationContext中获取对象,至于这个对象怎么初始化的?怎么完成组件依赖的?统统不用关心,spring框架提供了一系列工厂来管理这些bean对象。

也就是说,需要的bean对象原来是由你来new,你来管理,转变成交给spring框架来管理,对象的控制权由你,转移给了spring框架,这就是控制反转!

那么这里的IoC容器,其实就是一个Map,后面我们会继续解密。暂且按下不表。

当然了,一家餐馆要做出美味佳肴,原料和菜谱是必不可少的。IoC容器一样,要管理bean对象和它们之间的依赖关系,需要有相应的原材料和菜谱。

xml 复制代码
<bean id="a" class="com.xxx.A">
    <property name="b" ref="b">
</bean>

早期spring框架的玩家,对上面这个配置一定不会陌生!通过bean标签配置了一个bean,通过property属性标签,说明a对象,依赖一个b对象。这些是开发通过配置告诉spring框架,来,这就是原材料。

自然spring框架需要有与配置相应的原材料表示,这就是BeanDefinition。该实例负责bean对象的全部必要信息,包括:Class、访问控制、构造方法、参数、属性等。

原材料有了,菜谱呢?对应的菜谱是BeanDefinitionRegistry,和BeanFactory。BeanDefinitionRegistry负责抽象bean注册逻辑。Beanfactory负责抽象bean管理逻辑。配合起来天衣无缝!

  • BeanFactory核心方法
  • BeanDefinitionRegistry核心方法

且它们有一个共同的杰出后代:DefaultListableBeanFactory。作为默认的容器实现,同时实现了BeanDefinitionRegistry和BeanFactory,因此它同时负责bean的注册,管理工作。上一个图,直观一些。

了解了IoC相关的概念,再来看IoC的大致工作流程,主要有两个阶段。

2.2.IOC容器工作流程

  • 启动阶段

我们知道,要让容器管理bean对象,需要告诉容器相关的原材料信息,在实际开发中通常是你我提供的配置信息,比如xml配置或者注解配置,这些信息统称为Configuration MetaData,即配置元数据。

在spring 框架中,负责这个事情的是BeanDefinitionReader,该类负责加载、解析、分析Configuration MetaData信息,将这些信息封装成BeanDefinition,并注册到BeanDefinitionRegistry。这样一来启动阶段就算完成了。

  • bean实例化阶段

经过启动阶段,原材料准备好。当有某个使用方通过BeanFactory的getBean方法,获取某个bean对象时,容器会检查目标bean对象之前是否已经实例化。

如果有,则直接返回给使用方;

如果没有,则进入bean的实例化,容器会根据注册的BeanDefinition进行实例化,并为其注入依赖。实例化完成,返回给使用方。

需要注意的是,我们一直在说BeanFactory,事实上在实际应用中,用的更多的是另外一个容器实现:ApplicationContext。ApplicationContext是扩展至BeanFactory。它们两的区别在于:BeanFactory是延迟加载,而ApplicationContext是饥饿加载。

2.3.容器扩展机制

在整个spring容器管理bean生命周期过程中,不同阶段提供了对应的扩展点,这些扩展点使得我们在使用spring框架时,具备足够的灵活性。

在启动阶段,BeanFactoryPostProcessor可以在容器实例化对象之前,对注册到容器中的BeanDefinition对象进行修改,然后改变bean对象的行为。

要想自定义扩展类,需要实现接口BeanFactoryPostProcessor。实际应用中,你可能会需要自定义扩展多个BeanFactoryPostProcessor,为了保障多个BeanFactoryPostProcessor执行顺序,通常还需要扩展实现Ordered接口。

spring为我们提供了一个示例扩展:PropertyPlaceholderConfigurer。你一定还有这样的印象,在项目开发中,很多配置信息为了方便统一管理,在引用的地方,是这样的

xml 复制代码
${jdbc.driver}
${jdbc.url}
${jdbc.username}
${jdbc.passwd}

这些配置信息,在BeanDefinition对象中,是以占位符的形式存在。但当BeanFactory需要真正实例化bean对象时,需要将占位符替换成具体的配置信息。这个活谁来负责?没错,就是PropertyPlaceholderConfigurer。

相比较在启动阶段的扩展,大多数同学可能更熟悉BeanPostProcessor。BeanFactoryPostProcessor负责扩展bean定义;而BeanPostProcessor负责扩展实例化后的bean。它有两个方法:

  • postProcessBeforeInitialization:前置处理(执行初始化),即通常意义的init-method前
  • postProcessAfterInitialization:后置处理(销毁),即通常意义的destroy-method后

在实际应用中,你可以自定义一个注解,在某个bean上加上该注解,然后在BeanPostProcessor中检查该对象上,是否有注解?如果有,你便可以为所欲为的进行扩展!是不是很happy!

看一个spring框架提供的例子,经常能够看到各种Aware接口,它们的作用是在对象实例化完成以后,将Aware接口中定义的依赖注入到当前实例中,Aware的意思即注入,前面是什么,就注入什么。

比如ApplicationContextAware接口,如果你需要在你的bean对象中,获取到ApplicationContext对象,你只需要让你的bean实现ApplicationContextAware接口,则万事大吉!

相关推荐
爱勇宝11 分钟前
没有 Fn 键关触控板?我做了一个双击即用的 Windows 小工具
前端·后端·程序员
沙湖遇雨44 分钟前
8.ByteBuf 的数据模型、生命周期和内存分配
后端
by组态1 小时前
Ricon组态系统API参考手册
前端·后端·物联网
再吃一根胡萝卜1 小时前
Agent 如何选择与生成 SQL —— Text2SQL 全链路详解
后端
苍何1 小时前
把操作流程直接录成 Skill,豆包太夯了!
后端
Go_error1 小时前
在 Go 服务层中如何优雅地管理事务?
后端·go
爱读源码的大都督2 小时前
DeepSeek面试官问:多租户 RAG 系统怎样实现细粒度权限控制?
后端·面试·架构
yxlalm2 小时前
5.3解决超卖问题
java·spring boot·超卖