【Spring Boot】掌握这些springboot知识,让你事半功倍

本文深入探讨Spring Boot的核心特性,包括自动配置、起步依赖、Actuator和CLI。重点剖析启动流程及自动配置实现原理,解释Spring IOC容器的工作机制,如BeanDefinition、BeanFactory和ApplicationContext。此外,文章还介绍了Spring Boot如何根据项目依赖自动配置相关组件,以及启动过程中的条件化配置。通过对Spring Boot启动秘密的揭示,有助于读者更好地理解和运用Spring Boot。
摘要由CSDN通过智能技术生成

因而 Spring Boot 应用本质上就是一个基于 Spring 框架的应用,它是 Spring 对“约定优先于配置”理念的最佳实践产物,它能够帮助开发者更快速高效地构建基于 Spring 生态圈的应用。

那 Spring Boot 有何魔法?自动配置、起步依赖、Actuator、命令行界面(CLI) 是 Spring Boot 最重要的 4 大核心特性。

其中 CLI 是 Spring Boot 的可选特性,虽然它功能强大,但也引入了一套不太常规的开发模型,因而这个系列的文章仅关注其他 3 种特性。

本文将为你打开 Spring Boot 的大门,重点为你剖析其启动流程以及自动配置实现原理。要掌握这部分核心内容,理解一些 Spring 框架的基础知识,将会让你事半功倍。

SpringBoot相关视频教程,可以看动力节点王鹤老师讲的springboot2,非常适合初学入门,这一套视频完全搞定了

视频资源:https://www.bilibili.com/video/BV1XQ4y1m7ex

抛砖引玉:探索 Spring IOC 容器

如果有看过 SpringApplication.run() 方法的源码,Spring Boot 冗长无比的启动流程一定会让你抓狂。

透过现象看本质,SpringApplication 只是将一个典型的Spring应用的启动流程进行了扩展,因此,透彻理解 Spring 容器是打开 Spring Boot 大门的一把钥匙。

Spring IOC 容器

可以把 Spring IOC 容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。

IOC 容器也是一样,你只需要告诉它需要某个 bean,它就把对应的实例(instance)扔给你,至于这个 bean 是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。

作为餐馆,想要做出菜肴,得知道菜的原料和菜谱,同样地,IOC 容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。

BeanDefinition 对象就承担了这个责任:容器中的每一个 bean 都会有一个对应的 BeanDefinition 实例。

该实例负责保存 bean 对象的所有必要信息,包括 bean 对象的 class 类型、是否是抽象类、构造方法和参数、其他属性等等。

当客户端向容器请求相应对象时,容器就会通过这些信息为客户端返回一个完整可用的 bean 实例。

原材料已经准备好(把 BeanDefinition 看做原料),开始做菜吧,等等,你还需要一份菜谱。

BeanDefinitionRegistry 和 BeanFactory 就是这份菜谱,BeanDefinitionRegistry 抽象出 bean 的注册逻辑。

而 BeanFactory 则抽象出了 bean 的管理逻辑,而各个 BeanFactory 的实现类就具体承担了 bean 的注册以及管理工作。

它们之间的关系就如下图:

BeanFactory、BeanDefinitionRegistry 关系图(来自:Spring 揭秘)


DefaultListableBeanFactory 作为一个比较通用的 BeanFactory 实现,它同时也实现了 BeanDefinitionRegistry 接口,因此它就承担了 bean 的注册管理工作。

从图中也可以看出,BeanFactory 接口中主要包含 getBean、containBean、getType、getAliases 等管理 bean 的方法。

而 BeanDefinitionRegistry 接口则包含 registerBeanDefinition、removeBeanDefinition、getBeanDefinition 等注册管理 BeanDefinition 的方法。

下面通过一段简单的代码来模拟 BeanFactory 底层是如何工作的:

这段代码仅为了说明 BeanFactory 底层的大致工作流程,实际情况会更加复杂。

比如 bean 之间的依赖关系可能定义在外部配置文件(XML/Properties)中、也可能是注解方式。

Spring IoC 容器的整个工作流程大致可以分为两个阶段:

①容器启动阶段

容器启动时,会通过某种途径加载 ConfigurationMetaData。除了代码方式比较直接外,在大部分情况下,容器需要依赖某些工具类。

比如:BeanDefinitionReader,它会对加载的 ConfigurationMetaData 进行解析和分析,并将分析后的信息组装为相应的 BeanDefinition。

最后把这些保存了 bean 定义的 BeanDefinition,注册到相应的 BeanDefinitionRegistry,这样容器的启动工作就完成了。

这个阶段主要完成一些准备性工作,更侧重于 bean 对象管理信息的收集,当然一些验证性或者辅助性的工作也在这一阶段完成。

来看一个简单的例子吧,过往,所有的 bean 都定义在 XML 配置文件中,下面的代码将模拟 BeanFactory 如何从配置文件中加载 bean 的定义以及依赖关系:

②Bean 的实例化阶段

经过第一阶段,所有 bean 定义都通过 BeanDefinition 的方式注册到 BeanDefinitionRegistry 中。

当某个请求通过容器的 getBean 方法请求某个对象,或者因为依赖关系容器需要隐式的调用 getBean 时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。

如果没有,则会根据注册的 BeanDefinition 所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方使用。

BeanFactory 只是 Spring IoC 容器的一种实现,如果没有特殊指定,它采用延迟初始化策略:只有当访问容器中的某个对象时,才对该对象进行初始化和依赖注入操作。

而在实际场景下,我们更多的使用另外一种类型的容器: ApplicationContext,它构建在 BeanFactory 之上,属于更高级的容器。

除了具有 BeanFactory 的所有能力之外,还提供对事件监听机制以及国际化的支持等。它管理的 bean,在容器启动时全部完成初始化和依赖注入操作。

Spring 容器扩展机制

IoC 容器负责管理容器中所有 bean 的生命周期,而在 bean 生命周期的不同阶段,Spring 提供了不同的扩展点来改变 bean 的命运。

在容器的启动阶段, BeanFactoryPostProcessor 允许我们在容器实例化相应对象之前,对注册到容器的 BeanDefinition 所保存的信息做一些额外的操作,比如修改bean定义的某些属性或者增加其他信息等。

如果要自定义扩展类,通常需要实现
org.springframework.beans.factory.config.BeanFactoryPostProcessor 接口。

与此同时,因为容器中可能有多个 BeanFactoryPostProcessor,可能还需要实现
org.springframework.core.Ordered 接口,以保证 BeanFactoryPostProcessor 按照顺序执行。

Spring 提供了为数不多的 BeanFactoryPostProcessor 实现,我们以
PropertyPlaceholderConfigurer 来说明其大致的工作流程。

在 Spring 项目的 XML 配置文件中,经常可以看到许多配置项的值使用占位符,而将占位符所代表的值单独配置到独立的 properties 文件。

这样可以将散落在不同 XML 文件中的配置集中管理,而且也方便运维根据不同的环境进行配置不同的值。这个非常实用的功能就是由
PropertyPlaceholderConfigurer 负责实现的。

根据前文,当 BeanFactory 在第一阶段加载完所有配置信息时,BeanFactory 中保存的对象的属性还是以占位符方式存在的,比如 ${jdbc.mysql.url}。


PropertyPlaceholderConfigurer 作为 BeanFactoryPostProcessor 被应用时,它会使用 properties 配置文件中的值来替换相应的 BeanDefinition 中占位符所表示的属性值。

当需要实例化 bean 时,bean 定义中的属性值就已经被替换成我们配置的值。

当然其实现比上面描述的要复杂一些,这里仅说明其大致工作原理,更详细的实现可以参考其源码。

与之相似的,还有 BeanPostProcessor,其存在于对象实例化阶段。跟 BeanFactoryPostProcessor 类似,它会处理容器内所有符合条件并且已经实例化后的对象。

简单的对比,BeanFactoryPostProcessor 处理 bean 的定义,而 BeanPostProcessor 则处理 bean 完成实例化后的对象。

BeanPostProcessor 定义了两个接口:

为了理解这两个方法执行的时机,简单的了解下 bean 的整个生命周期:

Bean 的实例化过程(来自:Spring 揭秘)


postProcessBeforeInitialization()方法与 postProcessAfterInitialization() 分别对应图中前置处理和后置处理两个步骤将执行的方法。

这两个方法中都传入了 bean 对象实例的引用,为扩展容器的对象实例化过程提供了很大便利,在这儿几乎可以对传入的实例执行任何操作。

注解、AOP 等功能的实现均大量使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值