关于Spring Boot 的相关知识

在过去两三年的Spring生态圈,最让人兴奋的莫过于Spring Boot框架。或许从命名上就能看出这个框架的设计初衷:快速的启动Spring应用。因而Spring Boot应用本质上就是一个基于Spring框架的应用,它是Spring对“约定优先于配置”理念的最佳实践产物,它能够帮助开发者更快速高效地构建基于Spring生态圈的应用。

 

 

文章提纲:
1、探索Spring IoC容器
2、JavaConfig与常见Annotation
3、SpringFactoriesLoader详解
4、Spring容器的事件监听机制
5、揭秘自动配置原理
6、Spring Boot应用启动的秘密

 

 

那Spring Boot有何魔法?自动配置、起步依赖、Actuator、命令行界面(CLI) 是Spring Boot最重要的4大核心特性,其中CLI是Spring Boot的可选特性,虽然它功能强大,但也引入了一套不太常规的开发模型,因而这个系列的文章仅关注其它3种特性。如文章标题,本文是这个系列的第一部分,将为你打开Spring Boot的大门,重点为你剖析其启动流程以及自动配置实现原理。要掌握这部分核心内容,理解一些Spring框架的基础知识,将会让你事半功倍。

 

1、探索Spring IoC容器

 

如果有看过 SpringApplication.run()方法的源码,Spring Boot冗长无比的启动流程一定会让你抓狂,透过现象看本质,SpringApplication只是将一个典型的Spring应用的启动流程进行了扩展,因此,透彻理解Spring容器是打开Spring Boot大门的一把钥匙。

 

1.1、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的注册以及管理工作。它们之间的关系就如下图:

1552290938598381.jpg

 

BeanFactory、BeanDefinitionRegistry关系图

 

DefaultListableBeanFactory作为一个比较通用的BeanFactory实现,它同时也实现了BeanDefinitionRegistry接口,因此它就承担了Bean的注册管理工作。从图中也可以看出:

BeanFactory接口中主要包含以下管理bean的方法

 

getBean
containBean
getType
getAliases

 

而BeanDefinitionRegistry接口则包含注册管理BeanDefinition的方法:

 

registerBeanDefinition
removeBeanDefinition
getBeanDefinition

 

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

1552290939754339.jpg

这段代码仅为了说明BeanFactory底层的大致工作流程,实际情况会更加复杂,比如bean之间的依赖关系可能定义在外部配置文件(XML/Properties)中、也可能是注解方式。Spring IoC容器的整个工作流程大致可以分为两个阶段:

 

①、容器启动阶段

 

容器启动时,会通过某种途径加载 ConfigurationMetaData。除了代码方式比较直接外,在大部分情况下,容器需要依赖某些工具类,比如: BeanDefinitionReader,BeanDefinitionReader会对加载的 ConfigurationMetaData进行解析和分析,并将分析后的信息组装为相应的BeanDefinition,最后把这些保存了bean定义的BeanDefinition,注册到相应的BeanDefinitionRegistry,这样容器的启动工作就完成了。这个阶段主要完成一些准备性工作,更侧重于bean对象管理信息的收集,当然一些验证性或者辅助性的工作也在这一阶段完成。

 

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

1552290939728630.jpg

 

②、Bean的实例化阶段

 

经过第一阶段,所有bean定义都通过BeanDefinition的方式注册到BeanDefinitionRegistry中,当某个请求通过容器的getBean方法请求某个对象,或者因为依赖关系容器需要隐式的调用getBean时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方法使用。

 

BeanFactory只是Spring IoC容器的一种实现,如果没有特殊指定,它采用采用延迟初始化策略:只有当访问容器中的某个对象时,才对该对象进行初始化和依赖注入操作。而在实际场景下,我们更多的使用另外一种类型的容器: ApplicationContext,它构建在BeanFactory之上,属于更高级的容器,除了具有BeanFactory的所有能力之外,还提供对事件监听机制以及国际化的支持等。它管理的bean,在容器启动时全部完成初始化和依赖注入操作。

 

1.2、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定义了两个接口:

1552290939814311.jpg

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

1552290940116731.jpg

 

Bean的实例化过程

 

postProcessBeforeInitialization()方法与 postProcessAfterInitialization()分别对应图中前置处理和后置处理两个步骤将执行的方法。这两个方法中都传入了bean对象实例的引用,为扩展容器的对象实例化过程提供了很大便利,在这儿几乎可以对传入的实例执行任何操作。注解、AOP等功能的实现均大量使用了 BeanPostProcessor,比如有一个自定义注解,你完全可以实现BeanPostProcessor的接口,在其中判断bean对象的脑袋上是否有该注解,如果有,你可以对这个bean实例执行任何操作,想想是不是非常的简单?

 

再来看一个更常见的例子,在Spring中经常能够看到各种各样的Aware接口,其作用就是在对象实例化完成以后将Aware接口定义中规定的依赖注入到当前实例中。比如最常见的 ApplicationContextAware接口,实现了这个接口的类都可以获取到一个ApplicationContext对象。当容器中每个对象的实例化过程走到BeanPostProcessor前置处理这一步时,容器会检测到之前注册到容器的ApplicationContextAwareProcessor,然后就会调用其postProcessBeforeInitialization()方法,检查并设置Aware相关依赖。看看代码吧,是不是很简单:

1552290940199416.jpg

最后总结一下,本小节内容和你一起回顾了Spring容器的部分核心内容,限于篇幅不能写更多,但理解这部分内容,足以让您轻松理解Spring Boot的启动原理,如果在后续的学习过程中遇到一些晦涩难懂的知识,再回过头来看看Spring的核心知识,也许有意想不到的效果。也许Spring Boot的中文资料很少,但Spring的中文资料和书籍有太多太多,总有东西能给你启发。

转载于:https://my.oschina.net/u/4099417/blog/3025322

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 答:Spring Boot是一个开源框架,可以让您快速搭建高效的Java应用程序。它可以帮助您减少许多样板代码,并且可以帮助您更轻松地将您的应用程序部署到生产环境。了解有关Spring Boot相关知识,可以参考官方文档:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/,也可以搜索一些Spring Boot教程。 ### 回答2: Spring Boot是一个用于构建独立的、生产级的Spring应用程序的开源框架。它使开发者可以快速、轻松地创建Spring应用程序,而无需过多的配置。下面是一些关于Spring Boot知识推荐: 1. 简单的配置:Spring Boot提供了一种简化配置的方式,使用约定大于配置的原则,许多常见的配置都可以通过默认值自动完成。 2. 自动配置:Spring Boot根据当前类路径上的依赖关系,自动为应用程序进行配置。这意味着开发者可以在不编写大量代码的情况下实现一些常见功能,如数据库连接、web安全等。 3. 内嵌的服务器:Spring Boot内嵌了常见的服务器,如Tomcat、Jetty,使得应用程序可以轻松地以独立的方式运行。 4. 开箱即用的特性:Spring Boot提供了许多开箱即用的特性,如健康监测、远程配置、日志管理等。这些特性使得开发者可以快速实现一些常见的功能需求。 5. 监控和管理:Spring Boot提供了一些监控和管理的功能,如应用程序健康检查、性能指标监控、远程调试等。 6. 集成测试支持:Spring Boot提供了一些用于集成测试的支持,例如自动配置的测试、随机端口绑定等。 7. 生产级性能:Spring Boot设计时考虑到了生产级性能需求,提供了一些性能优化的功能,使得应用程序可以在高并发环境下高效运行。 总之,Spring Boot为开发者提供了一个简化、快速构建Spring应用程序的框架,具有简单配置、自动配置、内嵌服务器、开箱即用的特性、监控和管理、集成测试支持以及生产级性能等特点。了解和掌握这些知识可以帮助开发者更好地使用和学习Spring Boot框架。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值