SpringBoot笔记(一)核心内容

image-20230710170222399
走进SpringBoot一站式开发
前置课程: 《Spring6核心内容》《SpringMvc6》《SpringSecurity6》《Java-9-17新特性篇》
提醒: 有些小伙伴好奇能不能不学SSM直接SpringBoot,这里声明一下,SpringBoot只是用于快速创建SSM项目的脚手架,就像是个外壳一样,离开了SSM核心内容就是个空壳,不要本末倒置了。
Spring Boot让您可以轻松地创建独立的、生产级别的Spring应用程序,并“直接运行”这些应用程序。SpringBoot为大量的第三方库添加了支持,能够做到开箱即用,简化大量繁琐配置,用最少的配置快速构建你想要的项目。在2023年,SpringBoot迎来了它的第三个大版本,随着SpringBoot 3的正式发布,整个生态也迎来了一次重大革新。
目前的最新版本以及对应的维护情况:

image-20230710174659973
可以看到,曾经的SpringBoot 2.5版本将会在2023年8月底终止商业支持,届时将不会再对这类旧版本进行任何维护,因此,将我们的老版本SpringBoot项目进行升级已经迫在眉睫,目前最强的3.1正式版会维护到2025年中旬。
在3.X之后的变化相比2.X可以说是相当大,尤其是其生态下的SpringSecurity框架,旧版本项目在升级之后API已经完全发生改变;以及内置Tomcat服务器的升级,Servlet也升级到5以上,从
javax
全新升级到jakarta
新包名;包括在3.X得到的大量新特性,如支持GraalVM打包本地镜像运行等;并且Java版本也强制要求为17版本。迁移到新版本不仅可以享受到免费维护支持,也可以感受Java17带来的全新体验。介绍了这么多,我们首先还是来看看SpringBoot功能有哪些:
- 能够创建独立的Spring应用程序
- 内嵌Tomcat、Jetty或Undertow服务器(无需单独部署WAR包,打包成Jar本身就是一个可以运行的应用程序)
- 提供一站式的“starter”依赖项,以简化Maven配置(需要整合什么框架,直接导对应框架的starter依赖)
- 尽可能自动配置Spring和第三方库(除非特殊情况,否则几乎不需要进行任何配置)
- 提供生产环境下相关功能,如指标、运行状况检查和外部化配置
- 没有任何代码生成,也不需要任何XML配置(XML是什么,好吃吗)
SpringBoot是现在最主流的开发框架,国内的公司基本都在使用,也是我们出去找工作一定要会的框架,它提供了一站式的开发体验,能够大幅度提高我们的开发效率。

image-20221122175719997
在SSM阶段,当我们需要搭建一个基于Spring全家桶的Web应用程序时,我们不得不做大量的依赖导入和框架整合相关的Bean定义,光是整合框架就花费了我们大量的时间,但是实际上我们发现,整合框架其实基本都是一些固定流程,我们每创建一个新的Web应用程序,基本都会使用同样的方式去整合框架,我们完全可以将一些重复的配置作为约定,只要框架遵守这个约定,为我们提供默认的配置就好,这样就不用我们再去配置了,约定优于配置!
而SpringBoot正是将这些过程大幅度进行了简化,它可以自动进行配置,我们只需要导入对应的启动器(starter)依赖即可。
完成本阶段的学习,基本能够胜任部分网站系统的后端开发工作,也建议同学们学习完SpringBoot之后寻找合适的队友去参加计算机相关的高校竞赛,这里有一些推荐:
项目类:
建议: 按照目前国内的环境,项目类竞赛并不会注重你编码水平有多牛,也不会注重你的项目用到了多牛的技术,这些评委老师技术怎么样我不多说,他们只会在乎你项目制作的功能怎么样,展示效果怎么样,有没有什么创新点,至于其他的,哪怕代码写成一坨屎都不会管你。并且项目最好是有专利证书或者软著,尤其是企业合作项目,已经投入生产的,特别吃香。如果你是白手起家的项目,即使你再努力地去做,也不可能打得过人家强大的项目背景。
比赛名称 | 难度 | 含金量 | 备注 |
创新创业大赛 | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️ | 这比赛没点背景很难,最好是专利项目或是企业合作项目 |
挑战杯 | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️ | 网传这是PPT大赛,不知真实性如何 |
中国大学生计算机设计大赛 | ⭐️⭐️⭐️ | ⭐️⭐️⭐️ | 这个比赛相对来说比较好拿奖,项目一定要有亮点 |
算法类:
建议: 这种竞赛越早开始培养越好,因为要背很多的题板和算法,很多人都是初中或者高中就开始打竞赛了,像团队类型的竞赛,如果自己比较菜,就去找大佬抱大腿吧,十个臭皮匠都顶不了诸葛亮;个人类型的竞赛也要多刷力扣,多背算法题,临时抱佛脚也是没有用的。
比赛名称 | 难度 | 含金量 | 备注 |
蓝桥杯 | ⭐️⭐️⭐️ | ⭐️⭐️⭐️ | 蓝桥杯建议参加前端/Java组,稍微简单一点,去C++就是找死 |
CCPC 天梯赛 | ⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️ | 不多说 |
ICPC ACM 大学生程序设计竞赛 | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️⭐️ | 这个难度非常大,最好是有大佬带,靠自己慢慢去学很难 |
打竞赛的过程是很辛苦的,付出很有可能没有回报,很多竞赛没有绝对的公平,多多少少有一些利益关系在里面,但是多参加一些竞赛哪怕没有得奖,还是可以收获到很多的,如果你通过这些比赛学到了很多,实际上得不得奖已经不重要了,自己内心的强大的才是真正的强大。
快速上手
要感受SpringBoot带来的快速开发体验,我们就从创建一个项目开始。
极速创建项目
在过去,我们创建一个SSM项目,需要先导入各种依赖,进行大量的配置,而现在,有了SpringBoot,我们可以享受超快的项目创建体验,只需要前往官网进行少量配置就能快速为你生成一个SpringBoot项目模版:https://start.spring.io/

image-20230711124041648
不过,为了方便,IDEA已经将这个工具集成到内部了,我们可以直接在IDEA中进行创建,效果是一样的,首先在新建项目阶段,选择 Spring Initializr 类型:

image-20230711124216094
接着我们就可以配置项目的语言,并且选择项目需要使用的模块,这里我们简单选择两个依赖:

image-20230711124332819
如果一开始不清楚自己需要哪些模块,我们也可以后续自己手动添加对应模块的starter依赖,使用非常简单。
项目自动生成之后,可以看到Spring相关的依赖已经全部自动导入:

image-20230711124949017
并且也自动为我们创建了一个主类用于运行我们的SpringBoot项目:

image-20230711125025254
我们可以一键启动我们的SpringBoot项目:

image-20230711125447493
只不过由于我们没有添加任何有用的模块,也没有编写什么操作,因此启动之后项目就直接停止了。
常用模块快速整合
前面我们说了,SpringBoot的核心思想就是约定大于配置,能在一开始默认的就直接默认,不用我们自己来进行配置,我们只需要配置某些特殊的部分即可,这一部分我们就来详细体验一下。
我们来尝试将我们之前使用过的模块进行一下快速整合,可以看到在一开始的时候,我们没有勾选其他的依赖,因此这里只导入了最基本的
spring-boot-starter
依赖:所有的SpringBoot依赖都是以starter的形式命名的,之后我们需要导入其他模块也是导入
spring-boot-starter-xxxx
这种名称格式的依赖。首先我们还是从SpringMvc相关依赖开始。SpringBoot为我们提供了包含内置Tomcat服务器的Web模块,我们只需要导入依赖就能直接运行服务器:
我们不需要进行任何配置,直接点击启动:

image-20230711133113516
它真的做到了开箱即用,我们现在可以直接访问这个网站:

image-20230711133224425
可以看到成功响应了404页面,相比之前的大量配置,可以说方便了很多,我们到目前为止仅仅是导入了一个依赖,就可以做到直接启动我们的Web服务器并正常访问。
SpringBoot支持自动包扫描,我们不需要编写任何配置,直接在任意路径(但是不能跑到主类所在包外面去了)下创建的组件(如Controller、Service、Component、Configuration等)都可以生效,比如我们这里创建一个测试的Controller试试看:
重启之后,可以看到直接就能访问到,而这期间我们只是创建了对应的Controller却没有进行任何配置,这真的太方便了:

image-20230713225914578
包括一个对象现在也可以直接以JSON形式返回给客户端,无需任何配置:

image-20230715171140388
最后浏览器能够直接得到
application/json
的响应数据,就是这么方便,这都得归功于SpringBoot对应的start帮助我们自动将处理JSON数据的Converter进行了配置,我们不需要再单独去配置Converter了。不过SpringBoot官方默认使用的是Jackson
和Gson
的HttpMessageConverter来进行配置,不是我们之前教程中使用的FastJSON框架。我们最后来看看这个Start包含了哪些依赖:
里面包含了以下内容:
- spring-boot-starter 基础依赖starter
- spring-boot-starter-json 配置JSON转换的starter
- spring-boot-starter-tomcat 内置Tomcat服务器
- spring-web、spring-webmvc 不用多说了吧,之前已经讲过了
如果需要像之前一样添加WebMvc的配置类,方法是一样的,直接创建即可:
我们在SSM阶段编写的大量配置,到现在已经彻底不需要了。
同样的,我们来看看SpringSecurity框架如何进行整合,也是非常简单,我们只需要直接导入即可:
导入完成后,再次访问网站,就可以看到熟悉的登录界面了:

image-20230715182059681
我们没有进行任何配置,而是对应的Starter帮助我们完成了默认的配置,并且在启动时,就已经帮助我们配置了一个随机密码的用户可以直接登录使用:

image-20230715182323772
密码直接展示在启动日志中,而默认用户名称为
user
我们可以直接登录:
image-20230715182448770
同样没有进行任何配置,我们只需要添加对应的starter就能做到开箱即用,并且内置一套默认配置,自动帮助我们创建一个测试用户,方便我们快速搭建项目,同样的,如果要进行额外配置,我们只需要直接添加配置类即可:
同样的,我们也可以快速整合之前使用的模版引擎,比如Thymeleaf框架,直接上对应的Starter即可:
在默认情况下,我们需要在
resources
目录下创建两个目录:
image-20230715225833930
这两个目录是默认配置下需要的,名字必须是这个:
templates
- 所有模版文件都存放在这里
static
- 所有静态资源都存放在这里
我们只需要按照上面的样子放入我们之前的前端模版,就可以正常使用模版引擎了,同样不需要进入任何的配置,当然,如果各位小伙伴觉得不方便,我们后续也可以进行修改。
我们不需要在controller中写任何内容,它默认会将index.html作为首页文件,我们直接访问服务器地址就能展示首页了:

image-20230715230152860
这都是得益于约定大于配置的思想,开箱即用的感觉就是这么舒服,不过肯定有小伙伴好奇那现在要怎么才能像之前一样自己写呢,这个肯定还是跟之前一样的呗,该怎么写就怎么写。
我们最后再来看看Mybatis如何进行整合,同样只需要一个starter即可,这里顺便把MySQL的驱动加上:
注意这里的
mybatis-spring-boot-starter
版本需要我们自己指定,因为它没有被父工程默认管理。
image-20230715231142842
启动服务器时,我们发现这里出现了问题,导致无法启动。这是因为我们没有配置数据源导致的,虽然SpringBoot采用约定大于配置的思想,但是数据库信息只有我们自己清楚,而且变化多样,根本没有办法提前完成约定,所以说这里我们还是需要再配置文件中编写,至于如何编写配置文件我们会在下一节中进行讲解。
自定义运行器
在项目中,可能会遇到这样一个问题:我们需要在项目启动完成之后,紧接着执行一段代码。
我们可以编写自定义的ApplicationRunner来解决,它会在项目启动完成后执行:
当然也可以使用CommandLineRunner,它也支持使用@Order或是实现Ordered接口来支持优先级执行。
这个功能比较简单,不多做介绍了。
配置文件介绍
前面我们已经体验了SpringBoot带来的快捷开发体验,不过我们发现有些东西还是需要我们自己来编写配置才可以,不然SpringBoot项目无法正常启动,我们来看看如何编写配置。我们可以直接在
application.properties
中进行配置编写,它是整个SpringBoot的配置文件,比如要修改服务器的默认端口:
image-20230715232124133
这些配置其实都是各种Starter提供的,部分配置在Starter中具有默认值,我们即使不配置也会使用默认值,比如这里的8080就是我们服务器的默认端口,我们也可以手动修改它,来变成我们需要的。
除了配置已经存在的选项,我们也可以添加自定义的配置,来方便我们程序中使用,比如我们这里创建一个测试数据:

image-20230715234130924
我们可以直接在程序中通过
@Value
来访问到(跟我们之前Spring基础篇讲的是一样的)配置文件除了使用
properties
格式以外,还有一种叫做yaml
格式,它的语法如下:我们可以看到,每一级目录都是通过缩进(不能使用Tab,只能使用空格)区分,并且键和值之间需要添加冒号+空格来表示。
SpringBoot也支持这种格式的配置文件,我们可以将
application.properties
修改为application.yml
或是application.yaml
来使用YAML语法编写配置:现在我们来尝试为之前的数据源进行一下配置,这样才能正常启动我们的服务器:
配置完成后,我们就可以正常启动服务器了。
这里我们接续来测试一下MyBatis的配置,想要在SpringBoot中使用Mybatis也很简单,不需要进行任何配置,我们直接编写Mapper即可,这里我们随便创建一个表试试看:

image-20230716000431492
注意,在SpringBoot整合之后,我们只需要直接在配置类上添加
@MapperScan
注解即可,跟我们之前的使用方法是一样的:不过,为了方便,我们也可以直接为需要注册为Mapper的接口添加
@Mapper
注解,来表示这个接口作为Mapper使用:
image-20230716000755756
这样,即使不配置MapperScan也能直接注册为Mapper正常使用,是不是感觉特别方便?
访问接口测试一下:

image-20230716001311316
最后,我们再来介绍一下常见的配置项,比如SpringSecurity和SpringBootMvc配置:
更多的配置我们可以在后续的学习中继续认识,这些配置其实都是由Starter提供的,确实极大程度简化了我们对于框架的使用。
轻松打包运行
前面我们介绍了一个SpringBoot如何快捷整合其他框架以及进行配置编写,我们接着来看如何打包我们的SpringBoot项目使其可以正常运行,SpringBoot提供了一个非常便捷的打包插件,能够直接将我们的项目打包成一个jar包,然后使用java命令直接运行,我们直接点击Maven中的:

image-20230716155322915
点击之后项目会自动打包构建:

image-20230716155412252
打包完成之后,会在target目录下出现一个打包好的jar文件:

image-20230716155622849
我们可以直接在命令行中运行这个程序,在CMD中进入到target目录,然后输入:
这样就可以直接运行了:

image-20230716155834628
现在,我们的SpringBoot项目就可以快速部署到任何计算机了,只要能够安装JRE环境,都可以通过命令一键运行。
当然,可能也会有小伙伴好奇,怎么才能像之前一样在我们的Tomcat服务器中运行呢?我们也可以将其打包为War包的形式部署到我们自己环境中的Tomcat服务器或是其他任何支持Servlet的服务器中,但是这种做法相对比较复杂,不太推荐采用这种方式进行项目部署,不过我们这里还是介绍一下。
首先我们需要排除掉
spring-boot-starter-web
中自带的Tomcat服务器依赖:然后自行添加Servlet依赖:
最后将打包方式修改为war包:
接着我们需要修改主类,将其继承SpringBoot需要的Initializer(又回到SSM阶段那烦人的配置了,所以说一点不推荐这种部署方式)
最后,我们再次运行Maven 的package指令就可以打包为war包了:

image-20230716161834726
我们可以直接将其部署到Tomcat服务器中(如何部署已经在JavaWeb篇介绍过了)

image-20230716161921180
接着启动服务器就能正常访问了:

image-20230716162008831

image-20230716162030102
如果各位小伙伴需要在IDEA中进行调试运行,我们需要像之前一样配置一个Tomcat运行环境:

image-20230716162119751
这样就可以跟之前一样使用外部Tomcat服务器了:

image-20230716162156347
最后,我们需要特别介绍一下新的特性,在SpringBoot3之后,特别对GraalVM进行了支持:
GraalVM 是一种通用的虚拟机,最初由 Oracle 开发。它支持多种编程语言(例如 Java、JavaScript、Python 等),可以在不同的环境中运行,并提供高性能和低内存消耗。GraalVM的核心是一个即时编译器,它能够将各种语言的代码直接编译成本地机器码,以获得更高的性能。此外,GraalVM 还提供了一个强大的运行时环境,包括垃圾回收器、即时编译器、线程管理器等,可以提供更好的性能和可扩展性。GraalVM 的一个重要特性是它的跨语言互操作性。GraalVM 可以使不同语言之间的互操作更加容易。例如,你可以在 Java 代码中直接调用 JavaScript 函数,或者在 JavaScript 代码中直接调用 Java 类。这使得在不同语言之间共享和复用代码变得更加容易。总的来说,GraalVM 是一个开创性的技术,可以提供出色的性能和灵活性,同时也为多语言开发提供了更好的支持。它是一个非常有潜力的工具,可以用于构建高效的应用程序和解决方案。

image-20230716160131837
简而言之,我们的SpringBoot项目除了打包为传统的Jar包基于JVM运行之外,我们也可以将其直接编译为操作系统原生的程序来进行使用(这样会大幅提升程序的运行效率,但是由于编译为操作系统原生程序,这将无法支持跨平台)
首先我们需要安装GraalVM的环境才可以,这跟安装普通JDK的操作是完全一样的,下载地址:https://github.com/graalvm/graalvm-ce-builds/releases/tag/jdk-17.0.7

image-20230716162524422
下载好对应系统架构的GraalVM环境之后,就可以安装部署了,首先我们需要为GraalVM配置环境变量,将GRAALVM_HOME作为环境变量指向你的安装目录的bin目录下,接着我们就可以开始进行打包了(注意,SpringBoot项目必须在创建的时候添加了Native支持才可以,否则无法正常打包)
注意,一定要将
GRAALVM_HOME
配置到环境变量中,否则会报错:
image-20230716163645399
一切无误后,我们直接在IDEA中或是命令行中输入:
接着会自动安装
native-image
组件,然后进行本地镜像的编译(建议挂梯,不然卡一天都下不动)
image-20230716164025545
编译过程中比较消耗资源,建议CPU选择6核及以上,不然速度会很慢,编译完成之后如下图:

image-20230716164317582
这样一个系统原生的SpringBoot项目就打包好了,我们可以直接运行这个程序:

image-20230716165228609
不过由于Mybatis目前不支持Native-Image,所以只能期待有朝一日这些框架都能够完整支持原生镜像,让我们的程序运行效率更上一层楼。
至此,关于SpringBoot的快速上手教程就全部结束了,其实只要SSM阶段学的扎实,到了Boot阶段之后也是轻轻松松,下一部分我们将隆重介绍一下SpringBoot的日志模块。
日志系统介绍
SpringBoot为我们提供了丰富的日志系统,它几乎是开箱即用的。我们在之前学习SSM时,如果不配置日志,就会报错,但是到了SpringBoot阶段之后似乎这个问题就不见了,日志打印得也非常统一,这是为什么呢?
日志门面和日志实现
我们首先要区分一下,什么是日志门面(Facade)什么是日志实现,我们之前学习的JUL实际上就是一种日志实现,我们可以直接使用JUL为我们提供的日志框架来规范化打印日志。
而日志门面,如Slf4j,是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接口方法进行调用即可,由于它只是一个接口,并不是一个具体的可以直接单独使用的日志框架,所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体的日志系统来实现,这些具体的日志系统就有log4j、logback、java.util.logging等,它们才实现了具体的日志系统的功能。
日志门面和日志实现就像JDBC和数据库驱动一样,一个是画大饼的,一个是真的去做饼的。

img
但是现在有一个问题就是,不同的框架可能使用了不同的日志框架,如果这个时候出现众多日志框架并存的情况,我们现在希望的是所有的框架一律使用日志门面(Slf4j)进行日志打印,这时该怎么去解决?我们不可能将其他框架依赖的日志框架替换掉,直接更换为Slf4j吧,这样显然不现实。
这时,可以采取类似于偷梁换柱的做法,只保留不同日志框架的接口和类定义等关键信息,而将实现全部定向为Slf4j调用。相当于有着和原有日志框架一样的外壳,对于其他框架来说依然可以使用对应的类进行操作,而具体如何执行,真正的内心已经是Slf4j的了。

img
所以,SpringBoot为了统一日志框架的使用,做了这些事情:
- 直接将其他依赖以前的日志框架剔除
- 导入对应日志框架的Slf4j中间包
- 导入自己官方指定的日志实现,并作为Slf4j的日志实现层
打印项目日志信息
SpringBoot使用的是Slf4j作为日志门面,Logback(Logback 是log4j 框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J)作为日志实现,对应的依赖为:
此依赖已经被包含了,所以我们如果需要打印日志,可以像这样:
因为我们使用了Lombok,所以直接一个注解也可以搞定哦:
日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,SpringBoot默认只会打印INFO以上级别的信息,效果如下,也是使用同样的格式打印在控制台的:

image-20230716171120646
配置Logback日志
Logback官网:https://logback.qos.ch
和JUL一样,Logback也能实现定制化,我们可以编写对应的配置文件,SpringBoot推荐将配置文件名称命名为
logback-spring.xml
表示这是SpringBoot下Logback专用的配置,可以使用SpringBoot 的高级Profile功能,它的内容类似于这样:最外层由
configuration
包裹,一旦编写,那么就会替换默认的配置,所以如果内部什么都不写的话,那么会导致我们的SpringBoot项目没有配置任何日志输出方式,控制台也不会打印日志。我们接着来看如何配置一个控制台日志打印,我们可以直接导入并使用SpringBoot为我们预设好的日志格式,在
org/springframework/boot/logging/logback/defaults.xml
中已经帮我们把日志的输出格式定义好了,我们只需要设置对应的appender
即可:导入后,我们利用预设的日志格式创建一个控制台日志打印:
配置完成后,我们发现控制台已经可以正常打印日志信息了。
接着我们来看看如何开启文件打印,我们只需要配置一个对应的Appender即可:
配置完成后,我们可以看到日志文件也能自动生成了。
我们也可以魔改官方提供的日志格式,官方文档:https://logback.qos.ch/manual/layouts.html
这里需要提及的是MDC机制,Logback内置的日志字段还是比较少,如果我们需要打印有关业务的更多的内容,包括自定义的一些数据,需要借助logback MDC机制,MDC为“Mapped Diagnostic Context”(映射诊断上下文),即将一些运行时的上下文数据通过logback打印出来;此时我们需要借助org.sl4j.MDC类。
比如我们现在需要记录是哪个用户访问我们网站的日志,只要是此用户访问我们网站,都会在日志中携带该用户的ID,我们希望每条日志中都携带这样一段信息文本,而官方提供的字段无法实现此功能,这时就需要使用MDC机制:
通过这种方式,我们就可以向日志中传入自定义参数了,我们日志中添加这样一个占位符
%X{键值}
,名字保持一致:这样当我们向MDC中添加信息后,只要是当前线程(本质是ThreadLocal实现)下输出的日志,都会自动替换占位符。
自定义Banner展示
我们在之前发现,实际上Banner部分和日志部分是独立的,SpringBoot启动后,会先打印Banner部分,那么这个Banner部分是否可以自定义呢?答案是可以的。
我们可以直接来配置文件所在目录下创建一个名为
banner.txt
的文本文档,内容随便你:可以使用在线生成网站进行生成自己的个性Banner:https://www.bootschool.net/ascii
我们甚至还可以使用颜色代码来为文本切换颜色:
也可以获取一些常用的变量信息:
前面忘了,后面忘了,狠狠赚一笔!
多环境配置
在日常开发中,我们项目会有多个环境。例如开发环境(develop)也就是我们研发过程中疯狂敲代码修BUG阶段,生产环境(production )项目开发得差不多了,可以放在服务器上跑了。不同的环境下,可能我们的配置文件也存在不同,但是我们不可能切换环境的时候又去重新写一次配置文件,所以我们可以将多个环境的配置文件提前写好,进行自由切换。
由于SpringBoot只会读取
application.properties
或是application.yml
文件,那么怎么才能实现自由切换呢?SpringBoot给我们提供了一种方式,我们可以通过配置文件指定:接着我们分别创建两个环境的配置文件,
application-dev.yml
和application-prod.yml
分别表示开发环境和生产环境的配置文件,比如开发环境我们使用的服务器端口为8080,而生产环境下可能就需要设置为80或是443端口,那么这个时候就需要不同环境下的配置文件进行区分:这样我们就可以灵活切换生产环境和开发环境下的配置文件了。
SpringBoot自带的Logback日志系统也是支持多环境配置的,比如我们想在开发环境下输出日志到控制台,而生产环境下只需要输出到文件即可,这时就需要进行环境配置:
注意
springProfile
是区分大小写的!那如果我们希望生产环境中不要打包开发环境下的配置文件呢,我们目前虽然可以切换开发环境,但是打包的时候依然是所有配置文件全部打包,这样总感觉还欠缺一点完美,因此,打包的问题就只能找Maven解决了,Maven也可以设置多环境:
接着,我们需要根据环境的不同,排除其他环境的配置文件:
接着,我们可以直接将Maven中的
environment
属性,传递给SpringBoot的配置文件,在构建时替换为对应的值:这样,根据我们Maven环境的切换,SpringBoot的配置文件也会进行对应的切换。
最后我们打开Maven栏目,就可以自由切换了,直接勾选即可,注意切换环境之后要重新加载一下Maven项目,不然不会生效!
常用框架介绍
前面我们介绍了SpringBoot项目的基本搭建,相信各位小伙伴已经体验到SpringBoot 3带来的超强便捷性了,不过光靠这些还不够,我们还需要了解更多框架来丰富我们的网站,通过了解其他的SpringBoot整合框架,我们就可以在我们自己的Web服务器上实现更多更高级的功能,同时也是为了给我们后续学习前后端分离项目做准备。
邮件发送模块
都什么年代了,还在发传统邮件,我们来看看电子邮件。
我们在注册很多的网站时,都会遇到邮件或是手机号验证,也就是通过你的邮箱或是手机短信去接受网站发给你的注册验证信息,填写验证码之后,就可以完成注册了,同时,网站也会绑定你的手机号或是邮箱。
那么,像这样的功能,我们如何实现呢?SpringBoot已经给我们提供了封装好的邮件模块使用:
在学习邮件发送之前,我们需要先了解一下什么是电子邮件。
电子邮件也是一种通信方式,是互联网应用最广的服务。通过网络的电子邮件系统,用户可以以非常低廉的价格(不管发送到哪里,都只需负担网费,实际上就是把信息发送到对方服务器而已)、非常快速的方式,与世界上任何一个地方的电子邮箱用户联系。
虽说方便倒是方便,虽然是曾经的霸主,不过现在这个时代,QQ微信横行,手机短信和电子邮箱貌似就只剩收验证码这一个功能了。
要在Internet上提供电子邮件功能,必须有专门的电子邮件服务器。例如现在Internet很多提供邮件服务的厂商:新浪、搜狐、163、QQ邮箱等,他们都有自己的邮件服务器。这些服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中。
所有的用户都可以在电子邮件服务器上申请一个账号用于邮件发送和接收,那么邮件是以什么样的格式发送的呢?实际上和Http一样,邮件发送也有自己的协议,也就是约定邮件数据长啥样以及如何通信。

image-20230716172901937
比较常用的协议有两种:
- SMTP协议(主要用于发送邮件 Simple Mail Transfer Protocol)
- POP3协议(主要用于接收邮件 Post Office Protocol 3)
整个发送/接收流程大致如下:

img
实际上每个邮箱服务器都有一个smtp发送服务器和pop3接收服务器,比如要从QQ邮箱发送邮件到163邮箱,那么我们只需要通过QQ邮箱客户端告知QQ邮箱的smtp服务器我们需要发送邮件,以及邮件的相关信息,然后QQ邮箱的smtp服务器就会帮助我们发送到163邮箱的pop3服务器上,163邮箱会通过163邮箱客户端告知对应用户收到一封新邮件。
而我们如果想要实现给别人发送邮件,那么就需要连接到对应电子邮箱的smtp服务器上,并告知其我们要发送邮件。而SpringBoot已经帮助我们将最基本的底层通信全部实现了,我们只需要关心smtp服务器的地址以及我们要发送的邮件长啥样即可。
这里以163邮箱 https://mail.163.com 为例,我们需要在配置文件中告诉SpringBootMail我们的smtp服务器的地址以及你的邮箱账号和密码,首先我们要去设置中开启smtp/pop3服务才可以,开启后会得到一个随机生成的密钥,这个就是我们的密码。
配置完成后,接着我们来进行一下测试:
如果需要添加附件等更多功能,可以使用MimeMessageHelper来帮助我们完成:
最后,我们来尝试为我们的网站实现一个邮件注册功能,首先明确验证流程:请求验证码 -> 生成验证码(临时有效,注意设定过期时间) -> 用户输入验证码并填写注册信息 -> 验证通过注册成功!
接着我们就来着手写一下。
接口规则校验
通常我们在使用SpringMvc框架编写接口时,很有可能用户发送的数据存在一些问题,比如下面这个接口:
这个接口中,我们需要将用户名和密码分割然后打印,在正常情况下,因为用户名长度规定不小于5,如果用户发送的数据是没有问题的,那么就可以正常运行,这也是我们所希望的情况,但是如果用户发送的数据并不是按照规定的,那么就会直接报错:

image-20230716215850225
这个时候,我们就需要在请求进来之前进行校验了,最简单的办法就是判断一下:
虽然这样就能直接解决问题,但是如果我们的每一个接口都需要这样去进行配置,那么是不是太麻烦了一点?SpringBoot为我们提供了很方便的接口校验框架:
现在,我们可以直接使用注解完成全部接口的校验:
现在,我们的接口校验就可以快速进行配置了,一个接口就能搞定:

image-20230716220839816
不过这样依然会抛出一个异常,对用户不太友好,我们可以稍微处理一下,这里我们可以直接使用之前在SSM阶段中学习的异常处理Controller来自行处理这类异常:

image-20230716221420324
除了@Length之外,我们也可以使用其他的接口来实现各种数据校验:
验证注解 | 验证的数据类型 | 说明 |
@AssertFalse | Boolean,boolean | 值必须是false |
@AssertTrue | Boolean,boolean | 值必须是true |
@NotNull | 任意类型 | 值不能是null |
@Null | 任意类型 | 值必须是null |
@Min | BigDecimal、BigInteger、byte、short、int、long、double 以及任何Number或CharSequence子类型 | 大于等于@Min指定的值 |
@Max | 同上 | 小于等于@Max指定的值 |
@DecimalMin | 同上 | 大于等于@DecimalMin指定的值(超高精度) |
@DecimalMax | 同上 | 小于等于@DecimalMax指定的值(超高精度) |
@Digits | 同上 | 限制整数位数和小数位数上限 |
@Size | 字符串、Collection、Map、数组等 | 长度在指定区间之内,如字符串长度、集合大小等 |
@Past | 如 java.util.Date, java.util.Calendar 等日期类型 | 值必须比当前时间早 |
@Future | 同上 | 值必须比当前时间晚 |
@NotBlank | CharSequence及其子类 | 值不为空,在比较时会去除字符串的首位空格 |
@Length | CharSequence及其子类 | 字符串长度在指定区间内 |
@NotEmpty | CharSequence及其子类、Collection、Map、数组 | 值不为null且长度不为空(字符串长度不为0,集合大小不为0) |
@Range | BigDecimal、BigInteger、CharSequence、byte、short、int、long 以及原子类型和包装类型 | 值在指定区间内 |
@Email | CharSequence及其子类 | 值必须是邮件格式 |
@Pattern | CharSequence及其子类 | 值需要与指定的正则表达式匹配 |
@Valid | 任何非原子类型 | 用于验证对象属性 |
虽然这样已经很方便了,但是在遇到对象的时候,依然不太方便,比如:
此时接口是以对象形式接收前端发送的表单数据的,这个时候就没办法向上面一样编写对应的校验规则了,那么现在又该怎么做呢?
对应对象类型,我们也可以进行验证,方法如下:
这样当受到请求时,就会对对象中的字段进行校验了,这里我们稍微修改一下ValidationController的错误处理,对于实体类接收参数的验证,会抛出MethodArgumentNotValidException异常,这里也进行一下处理:
这样就可以正确返回对应的错误信息了。
接口文档生成(选学)
在后续学习前后端分离开发中,前端现在由专业的人来做,而我们往往只需要关心后端提供什么接口给前端人员调用,我们的工作被进一步细分了,这个时候为前端开发人员提供一个可以参考的文档是很有必要的。
但是这样的一个文档,我们也不可能单独写一个项目去进行维护,并且随着我们的后端项目不断更新,文档也需要跟随更新,这显然是很麻烦的一件事情,那么有没有一种比较好的解决方案呢?
当然有,那就是丝袜哥:Swagger
Swagger的主要功能如下:
- 支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需要自己手动编写接口文档了,对程序员来说非常方便,可以节约写文档的时间去学习新技术。
- 提供 Web 页面在线测试 API:光有文档还不够,Swagger 生成的文档还支持在线测试。参数和格式都定好了,直接在界面上输入参数对应的值即可在线测试接口。
结合Spring框架(Spring-doc,官网:https://springdoc.org/),Swagger可以很轻松地利用注解以及扫描机制,来快速生成在线文档,以实现当我们项目启动之后,前端开发人员就可以打开Swagger提供的前端页面,查看和测试接口。依赖如下:
项目启动之后,我们可以直接访问:http://localhost:8080/swagger-ui/index.html,就能看到我们的开发文档了:

image-20230717155121213
可以看到这个开发文档中自动包含了我们定义的接口,并且还有对应的实体类也放在了下面。这个页面不仅仅是展示接口,也可以直接在上面进行调试:

image-20230717155400761
这就非常方便了,不仅前端人员可以快速查询接口定义,我们自己也可以在线进行接口测试,直接抛弃PostMan之类的软件了。
虽然Swagger的UI界面已经可以很好地展示后端提供的接口信息了,但是非常的混乱,我们来看看如何配置接口的一些描述信息。首先我们的页面肯定要展示一下这个文档的一些信息,只需要一个Bean就能搞定:
这样我们的页面中就会展示自定义的文本信息了:

image-20230717165850714
接着我们来看看如何为一个Controller编写API描述信息:
我们可以直接在类名称上面添加
@Tag
注解,并填写相关信息,来为当前的Controller设置描述信息。接着我们可以为所有的请求映射配置描述信息:对于那些不需要展示在文档中的接口,我们也可以将其忽略掉:
对于实体类,我们也可以编写对应的API接口文档:
这样,我们就可以在文档中查看实体类简介以及各个属性的介绍了。
不过,这种文档只适合在开发环境下生成,如果是生产环境,我们需要关闭文档:
这样就可以关闭了。
项目运行监控(选学)
我们的项目开发完成之后,肯定是需要上线运行的,不过在项目的运行过程中,我们可能需要对其进行监控,从而实时观察其运行状态,并在发生问题时做出对应调整,因此,集成项目运行监控就很有必要了。
SpringBoot框架提供了
spring-boot-starter-actuator
模块来实现监控效果:添加好之后,Actuator会自动注册一些接口用于查询当前SpringBoot应用程序的状态,官方文档如下:https://docs.spring.io/spring-boot/docs/3.1.1/actuator-api/htmlsingle/#overview
默认情况下,所有Actuator自动注册的接口路径都是
/actuator/{id}
格式的(可在配置文件中修改),比如我们想要查询当前服务器的健康状态,就可以访问这个接口:http://localhost:8080/actuator/health,结果会以JSON格式返回给我们:
image-20230716205752392
直接访问:http://localhost:8080/actuator根路径,可以查看当前已经开启的所有接口,默认情况下只开启以下接口:
我们可以来修改一下配置文件,让其暴露全部接口:
重启服务器,再次获取可用接口就可以看到全部的信息了,这里就不全部搬出来了,只列举一些常用的:
比如我们可以通过 http://localhost:8080/actuator/info 接口查看当前系统运行环境信息:

image-20230716211517338
我们发现,这里得到的数据是一个空的,这是因为我们还需要单独开启对应模块才可以:
再次请求,就能获得运行环境相关信息了,比如这里的Java版本、JVM信息、操作系统信息等:

image-20230716211648263
我们也可以让health显示更加详细的系统状态信息,这里我们开启一下配置:
现在就能查看当前系统占用相关信息了,比如下面的磁盘占用、数据库等信息:

image-20230716212238191
包括完整的系统环境信息,比如我们配置的服务器8080端口:

image-20230716212456642
我们只需要通过这些接口就能快速获取到当前应用程序的运行信息了。
高级一点的还有线程转储和堆内存转储文件直接生成,便于我们对Java程序的运行情况进行分析,这里我们获取一下堆内存转储文件:http://localhost:8080/actuator/heapdump,文件下载之后直接使用IDEA就能打开:

image-20230716212801376
可以看到其中创建的byte数组对象计数达到了72020个,其中我们自己的TestController对象只有有一个:

image-20230716212920673
以及对应的线程转储信息,也可以通过http://localhost:8080/actuator/threaddump直接获取:

image-20230716214134109
实现原理探究(选学)
注意: 难度较大,本版块作为选学内容,在开始前,必须完成SSM阶段源码解析部分的学习。
我们在前面的学习中切实感受到了SpringBoot为我们带来的便捷,那么它为何能够实现如此快捷的开发模式,starter又是一个怎样的存在,它是如何进行自动配置的,我们现在就开始研究。
启动原理与实现
首先我们来看看,SpringBoot项目启动之后,做了什么事情,SpringApplication中的静态
run
方法:套娃如下:
我们发现,这里直接new了一个新的SpringApplication对象,传入我们的主类作为构造方法参数,并调用了非static的
run
方法,我们先来看看构造方法里面做了什么事情:通过阅读上面的源码,我们发现
getSpringFactoriesInstances
这个方法可以一次性获取指定类型已注册的实现类,我们先来研究一下它是怎么做到的。这里就要提到spring.factories
文件了,它是 Spring 仿造Java SPI实现的一种类加载机制。它在 META-INF/spring.factories 文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。这种自定义的SPI机制是 Spring Boot Starter 实现的基础。SPI的常见例子:
- 数据库驱动加载接口实现类的加载:JDBC加载不同类型数据库的驱动
- 日志门面接口实现类加载:SLF4J加载不同提供商的日志实现类
说白了就是人家定义接口,但是实现可能有很多种,但是核心只提供接口,需要我们按需选择对应的实现,这种方式是高度解耦的。
我们可以来看看
spring-boot-starter
依赖中怎么定义的,其中有一个很关键的点:这个
spring-boot-autoconfigure
是什么东西?实际上这个就是我们整个依赖实现自动配置的关键。打开这个依赖内部,可以看到这里确实有一个spring.factories
文件:
image-20230718233851593
这个里面定义了很多接口的实现类,比如我们刚刚看到的
ApplicationContextInitializer
接口:
image-20230718234021559
不仅仅是
spring-boot-starter
存在这样的文件,其他很多依赖,比如spring-boot-start-test
也有着对应的autoconfigure
模块,只不过大部分SpringBoot维护的组件,都默认将其中的spring.factories
信息统一写到了spring-boot-autoconfigure
和spring-boot-starter
中,方便后续维护。现在我们清楚,原来这些都是通过一个单独的文件定义的,所以我们来看看
getSpringFactoriesInstances
方法做了什么:所以
getSpringFactoriesInstances
其实就是通过读取所有META-INF/spring.factories
文件得到的列表,然后实例化指定类型下读取到的所有实现类并返回,这样,我们就清楚SpringBoot这一大堆参与自动配置的类是怎么加载进来的了。现在我们回到一开始的地方,目前SpringApplication对象已经构造好了,继续来看看
run
方法做了什么:至此,SpringBoot项目就正常启动了。
我们发现,即使是SpringBoot,也是离不开Spring最核心的ApplicationContext容器,因为它再怎么也是一个Spring项目,即使玩得再高级不还是得围绕IoC容器来进行么。所以说,SSM阶段学习的内容才是真正的核心,而SpringBoot仅仅是对Spring进行的一层强化封装,便于快速创建Spring项目罢了,这也是为什么一直强调不能跳过SSM先学SpringBoot的原因。
既然都谈到这里了,我们不妨再来看一下这里的ApplicationContext是怎么来的,打开
createApplicationContext
方法:我们发现在构造方法中
applicationContextFactory
直接使用的是DEFAULT:我们继续向下扒DefaultApplicationContextFactory的源码
create
方法部分:既然这里又是SpringFactoriesLoader加载ApplicationContextFactory实现,我们就直接去看有些啥:

image-20230719002638475
我们也不出意外地在
spring.factories
中找到了这两个实现,因为目前是Servlet环境,所以在返回时得到最终的结果,也就是生成的AnnotationConfigServletWebServerApplicationContext对象,也就是说到这里为止,Spring的容器就基本已经确定了,差不多可以开始运行了,下一个部分我们将继续介绍SpringBoot是如何实现自动扫描以及自动配置的。自动配置原理
既然主类已经在初始阶段注册为Bean,那么在加载时,就会根据注解定义,进行更多的额外操作。所以我们来看看主类上的
@SpringBootApplication
注解做了什么事情。我们发现,
@SpringBootApplication
上添加了@ComponentScan
注解,此注解我们此前已经认识过了,但是这里并没有配置具体扫描的包,因此它会自动将声明此接口的类所在的包作为basePackage,所以,当添加@SpringBootApplication
之后也就等于直接开启了自动扫描,我们所有的配置都会自动加载,但是一定注意不能在主类之外的包进行Bean定义,否则无法扫描到,需要手动配置。我们自己类路径下的配置、还有各种Bean定义如何读取的问题解决了,接着我们来看第二个注解
@EnableAutoConfiguration
,它就是其他Starter自动配置的核心了,我们来看看它是如何定义的:这里就是SSM阶段我们认识的老套路了,直接一手
@Import
,通过这种方式来将一些外部的类进行加载。我们来看看AutoConfigurationImportSelector做了什么事情:我们看到它实现了很多接口,包括大量的Aware接口,我们在SSM阶段也介绍过,实际上就是为了感知某些必要的对象,在加载时将其存到当前类中。
其中最核心的是
DeferredImportSelector
接口,它是ImportSelector
的子类,它定义了selectImports
方法,用于返回需要加载的类名称,在Spring加载ImportSelector时,会调用此方法来获取更多需要加载的类,并将这些类全部注册为Bean:到目前为止,我们了解了两种使用
@Import
有特殊机制的接口:ImportSelector(这里用到的)和ImportBeanDefinitionRegistrar(之前SSM阶段源码有讲)当然还有普通的@Configuration
配置类。为了后续更好理解我们可以来阅读一下
ConfigurationClassPostProcessor
的源码,实际上这个后置处理器是Spring中提供的,这是专门用于处理配置类的后置处理器,其中ImportBeanDefinitionRegistrar
,还有这里的ImportSelector
都是靠它来处理,不过当时Spring阶段没有深入讲解,我们来看看它到底是如何处理@Import
的:我们就接着来看,
ConfigurationClassParser
是如何进行解析的,直接进入parse
方法的关键部分:最后我们再来看最核心的
doProcessConfigurationClass
方法:不难注意到,虽然这里特别处理了
ImportSelector
对象,但是还针对ImportSelector
的子接口DeferredImportSelector
进行了额外处理,Deferred是延迟的意思,它是一个延迟执行的ImportSelector
,并不会立即进处理,而是丢进DeferredImportSelectorHandler,并且在我们上面提到的parse
方法的最后进行处理:我们接着来看
DeferredImportSelector
正好就有一个process
方法:最后经过ConfigurationClassParser处理完成后,通过
parser.getConfigurationClasses()
就能得到通过配置类导入那些额外的配置类或是特殊的类。最后将这些配置类全部注册BeanDefinition,然后就可以交给接下来的Bean初始化过程去处理了:最后我们再去看
loadBeanDefinitions
是如何运行的:这样,整个
@Configuration
配置类的底层配置流程我们就大致了解了。接着我们来看AutoConfigurationImportSelector是如何实现自动配置的,可以看到内部类AutoConfigurationGroup的process方法,它是父接口的实现,因为父接口是DeferredImportSelector
,根据前面的推导,很容易得知,实际上最后会调用process
方法获取所有的自动配置类:我们接着来看
getAutoConfigurationEntry
方法:我们接着往里面看:
到这里终于找到了:
我们可以直接找到:

image-20230725234543027
可以看到有很多自动配置类,实际上SpringBoot的starter都是依靠自动配置类来实现自动配置的,我们可以随便看一个,比如用于自动配置Mybatis框架的MybatisAutoConfiguration自动配置类:
可以看到里面直接将SqlSessionFactory和SqlSessionTemplate注册为Bean了,由于这个自动配置类在上面的一套流程中已经加载了,这样就不需要我们手动进行注册这些Bean了。不过这里有一个非常有意思的 @Conditional 注解,它可以根据条件来判断是否注册这个Bean,比如 @ConditionalOnMissingBean 注解就是当这个Bean不存在的时候,才会注册,如果这个Bean已经被其他配置类给注册了,那么这里就不进行注册。
经过这一套流程,简而言之就是SpringBoot读取
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件来确定要加载哪些自动配置类来实现的全自动化,真正做到添加依赖就能够直接完成配置和运行,至此,SpringBoot的原理部分就探究完毕了。自定义Starter项目
我们仿照Mybatis来编写一个自己的starter,Mybatis的starter包含两个部分:
因此我们也将我们自己的starter这样设计,我们设计三个模块:
- spring-boot-hello:基础业务功能模块
- spring-boot-starter-hello:启动器
- spring-boot-autoconifgurer-hello:自动配置依赖
首先是基础业务功能模块,这里我们随便创建一个类就可以了:
启动器主要做依赖管理,这里就不写任何代码,只写pom文件:
导入autoconfigurer模块作为依赖即可,接着我们去编写autoconfigurer模块,首先导入依赖:
接着创建一个HelloWorldAutoConfiguration作为自动配置类:
对应的配置读取类:
接着再编写
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件,并将我们的自动配置类添加即可:最后再Maven根项目执行
install
安装到本地仓库,完成。接着就可以在其他项目中使用我们编写的自定义starter了。————————————————
版权声明:本文为柏码知识库版权所有,禁止一切未经授权的转载、发布、出售等行为,违者将被追究法律责任。
原文链接:https://www.itbaima.cn/document/0k66v5r6slsfuog4
Loading...