目录
注意:本文转自 spring源码深度解析
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot将致力于在蓬勃发展的快速应用开发领域(RapidApplication Development)成为领导者。
Spring Boot特点如下:
创建独立的Spring应用程序;
嵌入的Tomcat,无须部署WAR文件;简化Maven配置;
自动配置Spring;
提供生产就绪型功能,如指标、健康检查和外部配置;
绝对没有代码生成,以及对XML没有配置要求。
当然,这样的介绍似乎太过于官方化,好像并没有帮助我们理解Spring Boot到底做了什么,我们不妨通过一个小例子来快速了解Spring Boot。
首先我们搭建一个maven工程,pom如下:
以上就是我们要准备的示例的所有内容,最后我们尝试启动main函数并在浏览器中输入localhost:8080,发现浏览器显示如图所示的界面。
这一切都似乎完全超乎了我们的预料,按照之前的经验,如果要构建这样一套MVC体系,似乎是非常麻烦的,至少要引入一大堆的pom依赖,同时,最为神奇的是整个过程中我们似乎根本没有启动过Tomcat,但是当我们运行函数的时候Tomcat居然自动起来了,而且还能通过浏览器访问,这一切都是怎么回事呢?这里留下悬念,我们稍后探索。
当然,如果你认为Spring Boot仅仅是封装了Tomcat那就大错特错了,一个流行的框架一定是一个理念的创新,它绝对不是一个简简单单的封装就能搞的定的。
第一个Starter
在我看来,Spring Boot之所以流行,是因为Spring starter模式的提出。Spring starter的出现,可以让模块开发更加独立化,相互间依赖更加松散以及可以更加方便地集成。从前言中介绍的例子来看,正是由于在pom文件中引入了下述代码:
以上实现为了尽量屏蔽Spring Boot基础理论以外的东西,把演示设计得尽量简单,如果是真实的业务,这个接口以及接口实现可能会非常复杂,甚至还会间接依赖于非常多的其他的bean。它基本上就是一个独立的业务模块,当然这个模块并不是自己部署,而是运行在依赖它的主函数中。如果我们开发到这种程度,想要主函数感知的话也不是不可以,但是至少要让主工程知道当前业务的bean路径并加入scan列表中,否则在Spring启动的过程中没有办法把client中所有的bean载入Spring容器,逻辑也就没法生效了,但是,随着业务的增长,模块也会越来越多、越来越分散,大量的配置在主函数中维护,这会造成主函数非常擁肿及冲突严重,而且根据职责划分原则,以上的例子中主模块只关心自己是否使用外部依赖的模块以及对应的接口就好了,再去让主模块感知对应的路径等细节信息显然是不合适的。于是乎,在Spring Boot出来之前我们会尝试把Scan等配置项写入XML里面,然后让主函数直接引用配置项,这样,主函数知道的事情就进一步减少了,但是还有没有更好的解决方式呢,或者,还有没有更好的办法能让主函数做更少的事情呢?Spring Boot做到了这一点,继续追加代码,添加自动配置项:
我们发现,在HelloServiceAutoConfiguration类中并没有逻辑实现,它存在的目的仅仅是通过注解进行配置的声明,我们可以在ComponentScan中加入这个模块的容器扫描路径。
当然,如果仅仅是到此,Starter还是没有开发完成,还需要最后一步,那就是声明这个配置文件的路径,在Spring的跟路径下建立META-INF/Spring.factories文件,并声明配置项路径(见图):
这给模块开发带来了非常大的方便,同时也为后续的模块拆分提供了便利,因为当业务逐渐复杂的时候我们会引入大量的中间件,而这些中间件的配置、依赖、以及初始化是非常麻烦的,现在有了Starter模式,它帮我们做到了只关注于逻辑本身。
那么,Spring Boot是如何做到的呢?
探索SpringApplication启动Spring
我们找到主函数入口SpringBootDemo1Application,发现这个入口的启动还是比较奇怪的,这也是Spring Boot启动的必要做法,那么,这也可以作为我们分析Spring Boot的入口:
如果读者看过之前的内容,就会知道,我们曾经在第5章介绍过Spring完整的初始化方案,其中就最为核心的就是SpringContext的创建、初始化、刷新等。那么我们可以直接进入查看其中的逻辑,同时,Spring作为一个全球都在使用的框架,会有非常多的需要考虑的问题,我们在阅读源码的过程中只需要关系核心的主流程,了解其工作原理,并在阅读的过程中感受它的代码风格以及设计理念就好了,如果真的追求理解每一行代码真的是非常耗时的一件事情,毕竟我们阅读源码的目的大多数是成长而不是真的要去维护Spring。
SpringContext创建
这里有个关键的判断,this.webEnvironment,如果读者没有看过代码很容易会忽略,但是这里将成为在前言中提到的Spring如何自动化启动Tomcat的关键,我们将会在后续章节详细介绍。
bean的加载
继续返回追踪prepareContext:
相信当读者看到BeanDefinitionLoader这个类的时候基本上就已经知道后续的逻辑了,bean的加载作为本书中最核心的部分早在第1章就已经开始分析了。