《SpringBoot 3:入门与应用实战》第 5 章 使用 Spring Boot 阅读笔记 9

📅 发布时间:2026/8/24 15:39:39
《SpringBoot 3:入门与应用实战》第 5 章 使用 Spring Boot 阅读笔记 9 《SpringBoot 3入门与应用实战》第 5 章 使用 Spring Boot 阅读笔记 9通过第一部分的学习相信读者已经对 Spring Framework 的基础有了足够的了解。在实际的项目开发中使用原生 Spring Framework 的工程很容易出现以下问题。工程搭建起来比较烦琐需要自行梳理工程中的依赖关系和依赖版本。项目中充斥着大量的 XML 配置文件、注解配置类等多种配置源并分散在工程的不同位置。针对这些问题Spring 的官方团队在历经波折后于 2014 年正式推出 Spring Boot这意味着基于 Spring Framework 的 Web 应用开发进入了一个新的模式开发者不必再去纠结烦琐的配置等问题而是专注于业务的开发。就其本身而言Spring Boot 不是一个全新的框架而是基于Spring Framework 的“二次封装”​所以一切底层都基于原生的 Spring Framework。5.1 Spring Boot 概述最初的 Spring Boot 要追溯到 2013 年当时 Spring Framework 开发团队就在着手准备 Spring Boot 项目的开发他们的想法是打造一个“支持不依赖外部容器的 Web 应用程序体系结构”​。2014 年 3 月 28 日Spring Boot 1.0.0 版本正式对外发布。时至今日Spring Boot 已经迭代到 3.x 版本Spring Boot 的社区活跃度极高这充分证明了 Spring Boot 作为当下最主流开发框架的地位。可以这样理解Spring Boot 是开发者与Spring Framework 之间的一道中间层它帮助开发者完成部分基于 Spring Framework 的项目配置、管理、部署等工作目的是为开发者“减负”​让开发者关心项目中的业务开发而不是把一部分精力浪费在项目环境搭建和琐碎的配置上。简单地说Spring Boot 可以轻松创建独立的、容易引入第三方技术的、生产级别的应用​。5.1.1 Spring Boot 的核心特性Spring Boot 设计之初的目的是简化基于 Spring Framework 的项目搭建和应用开发而不是代替 Spring Framework所以 Spring Boot 提供了以下几个核心特性来帮助开发者简化配置以及构建企业级应用。约定大于配置Spring Boot 对日常开发中比较常见的场景都约定了默认配置并基于自动装配机制将场景中通常必需的组件都注册好以此来实现少配置甚至不配置就能正常启动项目的效果。场景启动器Spring Boot 对常用的场景都进行了整合将这些场景中所需的依赖都收集并整理到一个依赖中并在其中添加了默认的配置使项目开发中只需导入一个依赖即可实现技术场景的整合。自动装配Spring Boot 基于 Spring Framework 的模块装配 条件装配可以在具体的场景下自动引入所需的配置类并解析执行并且可以根据项目代码中已经配置的内容动态注册组件以实现约定大于配置的效果。嵌入式 Web 容器Spring Boot 在运行时可以不依赖外部的 Web 容器而是使用内部嵌入式的 Web 容器来支撑应用的运行也正因如此基于 Spring Boot 的应用可以直接以 jar 包的形式运行。生产级别的特性Spring Boot 提供了生产运维型的功能特性比如健康检查、监控指标、外部化配置等。5.1.2 Spring Boot 的体系Spring Boot 支持的常见场景。Spring WebMvc 和 Spring WebFlux— Web 应用开发。Thymeleaf 和 Freemarker— Web 视图渲染。Spring Security — 安全控制。Spring Data Access — 数据访问 SQL 和 NoSQL ​。Spring Cache — 缓存实现。Spring Message — 消息中间件 JMS 和 AMQP ​。Spring Quartz — 定时任务。Spring Distribution Transaction — 分布式事务( JTA )。Spring Session — 分布式 Session。Container Images — 容器镜像构建支持。可以发现 Spring Boot 可以整合的技术场景非常多项目需要用到特定的场景或技术时只需导入对应的启动器依赖之后编写少量配置甚至不编写配置就可以实现场景整合的效果。另外基于场景启动器的整合不需要开发者考虑版本问题因为 Spring Boot 早已帮助开发者考虑并适配好。本书使用 Spring WebMvc 指代基于 Servlet 的 Web 开发读者可能对 Spring WebMvc 的更熟悉叫法是 Spring MVC这两者指代的是同一项技术。为了更好、更清楚地区分 WebMvc 与 WebFlux本书后续提到的所有 Spring MVC 简称为 WebMvc。5.2 Spring Boot 快速使用了解 Spring Boot 的理论基础知识后下面通过一个简单工程体会 Spring Boot 的项目构建和快速开发。5.2.1 创建项目创建基于 Spring Boot 的项目方式有两种常用的方式。1.基于 Spring Initializr表单中的可选项较多简单说明如下。Type项目构建工具可选 Maven 或 Gradle。Language项目编程所使用的语言可选 Java、Kotlin、Groovy。Spring Boot选择所使用 Spring Boot 的版本注意此处只能选择最新 RELEASE 版和紧跟着要“转正”的 SNAPSHOT 版​。Project Metadata项目的基本信息包含 Group、Artifact 以及 Spring Boot 启动类所在的包、打包方式、Java 语言版本等。Dependencies项目所使用的依赖在这个位置可以搜索并选择 Spring Boot 预先准备好的一些场景启动器​。在本节的演示中我们只选择 Web目录下的 “Spring Web” 即可。2.使用 Maven/Gradle 手动创建使用 Spring Initializr 的方式本质是使用固定代码模板生成的 Maven/Gradle 项目。在 IDEA 中创建一个 Module 模块。pom.xml 文件中需要继承父工程 spring-boot-starter-parent所有基于 Spring Boot 的工程都必须继承该父工程​声明 Java 的版本并添加 spring-boot-starter-web 依赖和 spring-boot-maven-plugin 插件即可完成基于 WebMvc 的场景整合。随后在工程的 src/main/java 目录下创建一个 com.yangjunbo.quickstart 包并在其中创建一个 Spring Boot 的主启动类SpringBootQuickstartApplication。主启动类的编写方式是固定的在类上标注 SpringBootApplication 注解并声明 main 方法使用SpringApplication 驱动运行。如此编写完毕就可以运行 main 方法启动工程。3.启动工程当实际运行main方法后控制台会打印很多信息。一个很大的 Spring 线条图我们称之为 “Banner”​。Tomcat initialized with port 8080 (http)工程中附带了一个 Tomcat并将在 8080 端口初始化。Starting Servlet engine: [Apache Tomcat/11.0.24]​内置的Tomcat版本为10.1.8。Root WebApplicationContext: initialization completed in 559 ms内部有一个嵌入式的 WebApplicationContext它是 ApplicationContext 的子实现。Tomcat started on port 8080 (http) with context path ‘/’Tomcat 成功运行在 8080 端口当前工程的 context-path 为 /。Started SpringbootQuickstartAApplication in 1.304 seconds (process running for 1.962)程序运行共耗时 1.304 秒。5.2.2 快速编写接口Spring MVC 底层基于 Servlet 开发下面编写一个类似于 Servlet 的组件体会一下 Spring Boot 的开发之迅速。新建一个 controller 包并在其中创建 HelloController 类定义一个 hello 方法用于接收请求并响应。简单解释这段代码的含义。RestController模式注解 Controller 的派生注解被 RestController 标注后当前类中所有标注了 RequestMapping或派生注解的方法会将方法的返回值响应到客户端浏览器如果返回值是对象还会被序列化为 JSON 格式的数据。GetMapping(“/hello”)当前方法是一个支持 GET 方式请求的 HTTP 接口请求路径为 /hello。编写完成后运行预期是当项目启动后访问 /hello 请求可以响应 “hello SpringBoot” 的字符串内容。再次运行 SpringBootQuickstartApplication 主启动类访问 http://localhost:8080/hello可以看到浏览器成功接收到响应 “hello Spring Boot”这意味着基于 Spring MVC 的接口开发完成。5.2.3 打包运行Spring Boot 的强大特性之一是 “直接运行”。可以将当前的工程打成一个 jar 包。找到当前工程的 pom.xml 文件在文件所属目录下使用命令行执行 mvn clean package 命令可以在生成的 target 目录下找到一个 jar 包。使用命令行执行 java -jar xxx.jar可以发现这个 jar 包已被成功启动并且内置的 Tomcat 也成功运行在 8080 端口。再次访问 http://localhost:8080/hello依然可以获得正确的响应这就印证了 “直接运行” 的概念Spring Boot 支持使用嵌入式 Web 容器将工程制作成独立可运行的 jar 包通过运行 jar 包就可以直接启动工程。支撑 Spring Boot 工程打包直接运行的依赖是 pom.xml 文件中的 spring-boot-maven-plugin 插件如果将该插件去掉则打包后无法通过 java -jar 命令启动。5.2.4 修改配置Spring Boot 中默认导入的 Tomcat 会在 8080 端口上运行。如果我们需要修改运行的端口号对于传统的 Tomcat 需要找到 server.xml 文件并修改配置而 Spring Boot 中只需要修改 application.properties 或 application.yml 文件中的内容。修改之后重新运行主启动类在控制台中可以发现 Tomcat 的运行端口已经改变此时再访问http://localhost:8080/hello 就会失效需要改变访问路径为 http://localhost:8888/hello 才能生效。5.3 Spring Boot 的依赖管理通过 5.2 节的快速使用可以感受到 Spring Boot 的功能之强大和使用之便利而这背后的强大支撑源自两大特性分别是本节要讲解的依赖管理和 5.4 节的自动装配。在刚开始搭建基于 Spring Boot 的应用时pom.xml 文件中只导入了一个 spring-boot-starter-web 依赖就完成了整个WebMvc 场景的开发。如果观察 IDE 中的工程依赖可以发现该模块中导入了包括 Spring 系列的 jar 包、与 JSON 处理相关的 Jackson 工具、Tomcat 服务器等依赖而我们实际没有自己编写这些依赖甚至连它们的版本号都没有声明这背后的机制就源自 Spring Boot 强大的依赖管理机制。5.3.1 场景启动器Spring Boot 官方提供了一组事先制作好的 pom 依赖这种依赖有一个专有名词叫 “场景启动器”它们都以相同的命名规范定义所有 Spring Boot 内置的依赖都以 “spring-boot-starter” 开头不同的后缀代表不同的依赖坐标分别指代不同场景下的启动器如 spring-boot- starter-web代表基于 Servlet 的 WebMvc 开发场景启动器spring-boot-starter-aop 代表启用 AOP 特性的开发场景启动器spring-boot-starter-jdbc 代表原生 JDBC 支持的开发场景启动器等。关于详细的依赖坐标列表读者可以参考 GitHub 中 Spring Boot 工程的 spring-boot-projects/spring-boot-starters 子工程或者直接从 Maven 的中央仓库中查看 groupId 为 “org.springframework.boot” 的发行版依赖即可。此外针对 Spring Boot 官方没有整合的技术许多第三方框架也推出了自己整合 Spring Boot 的方案此称之为“第三方场景启动器”比如MyBatis 中推出的 mybatis-spring- boot-starter。具体来看以5.2节的 springboot-01-quickstart 工程为例我们导入的 spring- boot-starter-web 依赖中包含一系列依赖其中包含 WebMvc 系列的依赖、Tomcat 的依赖、Jackson 的依赖。由于我们使用 Maven 来构建项目而 Maven 有一个依赖传递的机制假设 A 依赖 B而 B 又依赖 C则 A 无须显式声明依赖 C借助 B 即可拥有对 C 的依赖​通过这个机制就可以把一个场景中的所有依赖全部导入即引入一个依赖坐标底层由 Maven 帮我们导入了非常多的依赖。5.3.2 版本管理在编写上述示例时根本没有考虑导入依赖的版本问题在第 24 章中我们导入的所有依赖都有明确的版本号声明而在 5.2 节中我们导入的 spring-boot- starter-web 依赖并没有标注版本号而这一切是由于 pom.xml 文件中给当前工程指定了一个父工程 spring-boot-starter-parent这里面暗藏玄机。借助 IDE 打开 spring-boot-starter-parent 的 pom.xml 文件可以发现它继承了另一个父工程 spring-boot-dependencies而在这个父工程中我们可以从 标签中发现问题的奥秘对于 Spring Boot 每一个版本中内部整合的所有技术在 spring-boot-dependencies 中都已经声明了对应的版本另外在 标签的下方还有一个 标签其中统一定义了所有 Spring Boot 内置支持的依赖信息和版本这样做的效果是我们在搭建工程引入依赖时只需要引入场景启动器而无须关心内部整合了哪些组件和版本适配。5.4 Spring Boot 的自动装配Spring Boot 之所以能帮我们快速地搭建开发环境内部设计了两大核心特性依赖管理和自动装配。依赖管理统一定义了所有 Spring Boot 内置支持的依赖信息和版本。自动装配当导入一个场景启动器时Spring Boot 会默认向 IOC 容器中注册非常多的组件。5.4.1 组件自动装配如果在阅读本书之前了解了有关传统的 SSM 甚至 SSH 框架的整合应该了解整合的内容中包含很多组件配置​。关于这些组件的注册在我们搭建基于 Spring Boot 的工程时都没有见到过这是否意味着工程中没有注册组件为了验证组件是否存在我们可以尝试获取 IOC 容器并打印其中所有 Bean 的名称。SpringApplication 类的 run 方法会返回一个 ConfigurableApplicationContext关于这个接口在第 4 章中已经讲解过它是 “可写” 的 IOC 容器模型它拥有一个 getBeanDefinitionNames 方法通过该方法可以获取 IOC 容器中所有 Bean 的名称。packagecom.yangjunbo.springboot.quickstart;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.ConfigurableApplicationContext;importjava.util.Arrays;SpringBootApplicationpublicclassSpringbootQuickstartApplication{publicstaticvoidmain(String[]args){ConfigurableApplicationContextctxSpringApplication.run(SpringbootQuickstartApplication.class,args);Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);}}执行 main 方法启动工程观察控制台中的输出可以发现有一个 characterEncodingFilter同时还打印了诸如 dispatcherServlet、mvcViewResolver 等组件说明默认情况下当我们导入一个场景启动器时Spring Boot 会默认帮我们向 IOC 容器中注册非常多的组件。5.4.2 默认组件扫描上面编写的工程中定义了一个 HelloController这个类放在 com.yangjunbo.springboot.quickstart.controller 包中而 Spring Boot 的主启动类放在父包 com.yangjunbo.springboot.quickstart 中。如此编写之后 HelloController 也在工程启动后装载到了 IOC 容器中这就意味着 Spring Boot有一个默认的组件扫描规则扫描主启动类所在包及子包下的所有组件。为了验证这一机制我们可以将 HelloController 移至其他包中此时如果再启动工程则控制台中打印的 Bean 名称中不会再包含helloController而且我们再访问 /hello 请求时也会提示404错误这就说明组件扫描的默认规则的确是以 Spring Boot 主启动类为基准。如果需要修改组件扫描的路径我们可以在 SpringBootApplication 注解中修改 scanBasePackages 或 scanBasePackageClasses 属性这两个属性分别对应 ComponentScan 注解的 basePackages 和 basePackageClasses 属性比如我们将工程的组件扫描根包改为com.yangjunbo.springboot此时再重启工程控制台中就会再次打印 helloController访问 /hello 请求时也可以正常得到响应。