Spring Boot开发的两大流派

image-20250524204200477

Spring Boot 从 2 开始,分为了两大流派:

  • 响应式栈(Reactive Stack )和 Servlet 栈(Servlet Stack )。

响应式栈(Reactive Stack )

  • 框架:Spring WebFlux ,是一个非阻塞的 Web 框架,充分利用多核下一代处理器的优势,能处理大量并发连接。
  • 底层支持:依赖 Netty、Servlet 3.1 + 容器 ,并通过响应式流适配器(Reactive Streams Adapters)实现。
  • 相关组件
    • Spring Security Reactive:响应式安全组件。
    • Spring WebFlux:核心的响应式 Web 框架。
    • Spring Data Reactive Repositories:支持 Mongo、Cassandra、Redis、Couchbase、R2DBC 等数据库的响应式数据仓库。

响应式栈主要好处和特点是很好的压榨了多核心 CPU 的能力,基于缓冲区机制和调度器去调度 CPU ,去处理大量的请求和实现高并发这种功能。这其实也就是我们常说的 非阻塞 I/O,以 Spring WebFlux 为核心框架 ,基于异步非阻塞方式,不阻塞线程等待 I/O 操作完成,充分利用多核处理器优势,能高效处理大量并发连接,提升系统吞吐量。支持多种异步框架,依赖 Netty 等框架及 Servlet 3.1 + 容器,提供异步 I/O 能力。

而且响应式栈基于响应式的编程模型,遵循响应式流规范,基于事件驱动的异步数据流处理模式,少量线程就能处理众多请求,资源利用高效。

Servlet 栈(Servlet Stack )

  • 框架:Spring MVC ,基于 Servlet API 构建,采用同步阻塞 I/O 架构,一个请求对应一个线程模型。
  • 底层支持:依赖 Servlet 容器和 Servlet API 。
  • 相关组件
    • Spring Security:传统安全组件。
    • Spring MVC:传统的 MVC 框架。
    • Spring Data Repositories:支持 JDBC、JPA、NoSQL 等数据库的数据仓库。

Spring MVC 架构基于 Servlet API 构建,采用同步阻塞 I/O 架构,每个请求占用一个线程,请求处理过程中线程会阻塞等待 I/O 操作完成。这样就是使用了传统的分时 CPU,适合小规模的普通应用,因为传统编程模型,是较为传统、开发者熟悉的编程模型,代码编写、阅读和调试相对容易,基于命令式编程。运行依赖 Servlet 容器,如 Tomcat、Jetty 等。

响应式栈处理高并发时,用少量线程和资源;Servlet 栈高并发下需较多线程,资源消耗大,线程池线程耗尽时性能受影响。响应式栈适合实时性要求高、高并发场景,如物联网、金融交易系统;Servlet 栈适合传统 Web 应用开发,对并发要求不是极高的场景 。

Spring Boot 概述

Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的创建、运行、调试、部署等。使用 Spring Boot 可以做到专注于 Spring 应用的开发,而无需过多关注 XML 的配置。Spring Boot 使用“习惯优于配置”的理念,简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题。使用 Spring Boot 可以不用或者只需要很少的 Spring 配置就可以让企业项目快速运行起来。

  • 提供预配置的依赖包
  • 按照使用习惯解决依赖问题
  • 极大减少XML配置
  • 开箱即用的应用程序架构

SpringBoot是一个快速开发的框架,能过快速整合第三方框架,他是如何快速整合的呢?其实他是的基本原来是Maven依赖关系,Maven的集成,完全采用注解化,简化XML配置,内嵌HTTP服务器(Tomcate,jetty),默认嵌入Tomcate,最终以Java应用程序进行执行。

所以说,Spring Boot 是开发者和 Spring Framework 本身框架的中间层,帮助开发者统筹管理应用的配置,提供基于实际开发中常见配置的默认处理(即习惯优于配置),简化应用的开发,简化应用的运维;

总的来说,其目的 Spring Boot 就是为了对 Java web 的开发进行“简化”和加“快”速度,简化开发过程中引入或启动相关 Spring 功能的配置。这样带来的好处就是降低开发人员对于框架的关注点,可以把更多的精力放在自己的业务代码上。

同时随着微服务概念的推广和实践,Spring Boot 的精简理念又使其成为Java微服务开发的不二之选,也可以说,Spring Boot 其实就是为了微服务而生的 Java web 框架。

SpringBoot与SpringMVC 的区别是什么,说白了,就是 Spring Boot Web 组件默认集成 SpringMVC 框架, SpringMVC3.0 以后支持注解方式使用 java 代码启动 SpringMVC 。

与 Spring Framework衔接并且起步

我们已经在前面详细介绍了Spring框架,它的主要功能包括IoC容器、AOP支持、事务支持、MVC开发以及强大的第三方集成功能等。

那么,Spring Boot又是什么?它和Spring是什么关系?

Spring Boot是一个基于Spring的套件,它帮我们预组装了Spring的一系列组件,以便以尽可能少的代码和配置来开发基于Spring的Java应用程序。

如果把应用开发比作组装汽车

  • Spring Framework = 汽车零部件(发动机、传动、轮胎、底盘等)
  • Spring Boot = 预装好的整车(可以直接上路,需要时可以换配件)

因此,Spring Boot和Spring的关系就是整车和零部件的关系,它们不是取代关系,试图跳过Spring直接学习Spring Boot是不可能的。

Spring Boot的目标就是提供一个开箱即用的应用程序架构,我们基于Spring Boot的预置结构继续开发,省时省力。

本章我们将详细介绍如何使用Spring Boot。

本教程使用的Spring Boot版本是3.x版,如果使用Spring Boot 2.x则需注意,两者有以下不同:

Spring Boot 2.x Spring Boot 3.x
Spring版本 Spring 5.x Spring 6.x
JDK版本 >= 1.8 >= 17
Tomcat版本 9.x 10.x
Annotation包 javax.annotation jakarta.annotation
Servlet包 javax.servlet jakarta.servlet
JMS包 javax.jms jakarta.jms
JavaMail包 javax.mail jakarta.mail

Spring Boot 3.x的重要变化:

1
2
3
4
5
6
7
// Spring Boot 2.x
import javax.servlet.http.HttpServletRequest;
import javax.annotation.PostConstruct;

// Spring Boot 3.x
import jakarta.servlet.http.HttpServletRequest;
import jakarta.annotation.PostConstruct;

注意:Spring Boot 3.x要求JDK 17+,并且包名从javax.*迁移到jakarta.*

如果使用Spring Boot的其他版本,则需要根据需要调整代码。

Spring Boot的核心功能(核心特性)

  • 可独立运行的Spring项目:Spring Boot 可以以 jar 包的形式独立运行。

    1
    2
    # 直接运行jar包
    java -jar myapp.jar
  • 内嵌的Servlet容器:Spring Boot可以选择内嵌 Tomcat、Jetty 或者 Undertow,无须以 war 包形式部署项目。

    1
    2
    3
    4
    5
    6
    7
    # application.yml配置示例
    server:
    port: 8080
    servlet:
    context-path: /api
    tomcat:
    max-threads: 200
  • 简化的Maven配置:Spring 提供推荐的基础 pom.xml 文件来简化 Maven 配置。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- 父POM继承 -->
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.0</version>
    <relativePath/>
    </parent>

    <!-- Starter依赖 -->
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    </dependencies>
  • 自动配置Spring以及第三方库:Spring Boot 会根据项目依赖来自动配置Spring 框架,极大地减少项目要使用的配置。也就是所谓的 约定大于配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @SpringBootApplication
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }

    // @SpringBootApplication 等价于:
    // @Configuration + @EnableAutoConfiguration + @ComponentScan
  • 提供生产级特性 Actuator :提供可以直接在生产环境中使用的功能,如性能指标、应用信息和应用健康检查。

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    常用监控端点:

    • /actuator/health - 健康检查
    • /actuator/metrics - 性能指标
    • /actuator/info - 应用信息
    • /actuator/env - 环境配置
  • 拥有可选的 starter:简化应用的整合,为生产的各种场景准备了对应的依赖坐标,导入一个就能全部导入

    Starter依赖生态

    Starter 名称 功能描述
    spring-boot-starter-web Web 开发(Spring MVC)
    spring-boot-starter-webflux 响应式 Web 开发
    spring-boot-starter-data-jpa JPA 数据访问
    spring-boot-starter-security Spring Security 安全
    spring-boot-starter-test 测试支持
    spring-boot-starter-redis Redis 缓存
  • 无代码生成和xml配置:Spring Boot 不生成代码。完全不需要任何 xml 配置即可实现 Spring 的所有配置。

    传统Spring配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!-- web.xml -->
    <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring-mvc.xml</param-value>
    </init-param>
    </servlet>

    <!-- spring-mvc.xml -->
    <context:component-scan base-package="com.example"/>
    <mvc:annotation-driven/>

    Spring Boot配置:

    1
    2
    3
    4
    5
    6
    @SpringBootApplication  // 一个注解搞定!
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }

快速整合原理

1
2
3
4
5
<!-- Spring Boot的魔法:starter依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Boot快速整合第三方框架的原理:

  1. Maven依赖管理:通过starter依赖自动引入相关组件
  2. 注解驱动:完全采用注解化配置,简化XML
  3. 内嵌服务器:默认嵌入Tomcat,支持Jetty、Undertow
  4. 自动配置:根据classpath自动配置组件

Spring Boot与微服务

Spring Boot的精简理念使其成为Java微服务开发的首选框架

  • 轻量级、快速启动
  • 独立运行,无需外部容器
  • 易于容器化部署
  • 完美支持Cloud Native应用

建议学什么

以尚硅谷的为例子

image-20250524204944287

Java 基础

  • Java 基础:熟练掌握 Java 语法,包括面向对象编程(类、对象、继承、多态等 )、异常处理、泛型、集合框架等。同时,Java 17 及以上版本特性也需了解,因为 Spring Boot3 与 Java 17 及更高版本兼容。
  • 函数式编程基础:理解 Lambda 表达式、函数式接口,Stream API 等函数式编程相关概念 ,这有助于理解和使用 Spring Boot3 中一些响应式编程和函数式风格的特性。

Spring Boot3 核心概念

  • 自动配置:Spring Boot3 能根据项目依赖和配置自动配置应用,像自动配置 Web 服务器、数据库连接池、缓存等。需明白其自动配置原理和机制,以及如何自定义配置覆盖默认配置。
  • 起步依赖:通过添加起步依赖(如 spring - boot - starter - web、spring - boot - starter - data - jpa 等),Spring Boot3 自动引入所需的其他依赖,要掌握常见起步依赖用途和使用场景。
  • 嵌入式服务器:内置 Tomcat、Jetty、Undertow 等嵌入式服务器,了解如何配置和使用它们,以及不同服务器的特点和适用场景。
  • Actuator:用于监控和管理 Spring Boot3 应用,提供健康检查、性能指标、环境信息等功能。学会使用 Actuator 暴露的端点监控应用运行状态。

配置相关

  • 配置文件:掌握 application.properties 和 application.yml 两种配置文件语法格式,以及如何配置常见项,如日志、数据源、Web 服务器端口等。了解配置文件外部化、配置文件优先级等知识。
  • 自定义配置与属性:学会通过 @Value 注解注入属性值,使用 @ConfigurationProperties 绑定配置属性到自定义类 。

Web 开发

  • RESTful API 开发:利用 Spring MVC(Spring Boot3 默认 Web 框架 )创建 RESTful API,掌握 @RestController@RequestMapping@GetMapping 等常用注解,以及请求参数处理、响应数据格式化等。
  • Thymeleaf 等模板引擎:若开发传统 Web 应用,了解 Thymeleaf 等模板引擎,用于渲染动态 HTML 页面。

数据访问

  • JPA(Java Persistence API):使用 spring - boot - starter - data - jpa 起步依赖集成 JPA,掌握 JPA 基本操作,如实体类定义、Repository 接口编写、数据库 CRUD 操作。
  • 其他数据访问技术:除 JPA 外,了解 Spring Data 对其他数据库(如 MySQL、PostgreSQL、Redis、MongoDB 等 )的支持和操作方式。

安全相关

  • Spring Security:集成 Spring Security 实现用户认证和授权,掌握基本认证方式(如表单认证、HTTP Basic 认证 )、授权机制(如基于角色的访问控制 RBAC )、密码加密等。

响应式编程

  • Reactor:理解响应式编程模型,掌握 Reactor 框架中 Mono(表示 0 或 1 个元素的异步序列 )和 Flux(表示 0 到多个元素的异步序列 )的使用,以及流操作符(如 map、filter、flatMap 等 )、线程调度、错误处理等。
  • Spring WebFlux:基于 Reactor 的响应式 Web 框架,了解其与 Spring MVC 的区别,学会使用 Spring WebFlux 开发异步、非阻塞的 Web 应用,处理高并发场景。
  • Spring Data R2DBC:用于响应式访问关系型数据库,掌握 R2dbc 驱动使用、DatabaseClient API 操作数据库,以及自定义 Repository、处理关联查询等。
  • Spring Security Reactive:在响应式编程模型下实现安全控制,了解 RBAC 权限模型配置、FilterChain 配置、ReactiveUserDetailsService 等。

其他

  • 项目构建与部署:掌握 Maven 或 Gradle 构建工具,学会打包项目(如生成可执行 JAR 或 WAR 包 )。了解项目在生产环境的部署方式,如容器化(Docker、Kubernetes )、负载均衡等。
  • 性能优化与调优:掌握配置文件优化(如设置合理线程池、连接池 )、使用缓存(@Cacheable 注解 )、异步处理(@Async 注解 )等性能优化技巧。
  • 日志管理:学会配置日志级别、输出格式等,使用日志记录应用运行信息,排查问题。

这一套方案的比较全面且比较基础的,Spring Boot3 还要很多别的东西

Spring Boot 官方文档:https://docs.spring.io/spring-boot/index.html

第一个 Spring Boot 程序

要了解Spring Boot,我们先来编写第一个Spring Boot应用程序,看看与前面我们编写的Spring应用程序有何异同。

目录结构

我们新建一个springboot-ergou的工程,创建标准的 Maven工程 目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
springboot-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ │ ├── DemoApplication.java
│ │ │ ├── controller/
│ │ │ │ └── HelloController.java
│ │ │ └── entity/
│ │ │ └── User.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── static/
│ └── test/
├── pom.xml
└── README.md

在存放源码的src/main/java目录中,Spring Boot对Java包的层级结构有一个要求。注意到我们的根package是edu.software.ergoutree.springbootpritical,下面还有其他子包。

但是,Spring Boot要求main()方法所在的启动类必须放到根package下,命名不做要求

依赖导入

我们再观察pom.xml,它的内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?xml version="1.0" encoding="UTF-8"?>
<!-- Maven项目对象模型(POM)文件,定义项目结构、依赖和构建配置 -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 继承Spring Boot的基础配置,提供依赖管理和插件配置 -->
<!-- 这是第一步,所有Spring Boot项目都必须继承这个夫项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
<relativePath/> <!-- 从Maven仓库查找父POM -->
</parent>

<!-- 项目基本信息 -->
<groupId>edu.software.ergoutree</groupId> <!-- 组织或项目的唯一标识符 -->
<artifactId>SpringBootPritical</artifactId> <!-- 项目的唯一标识符 -->
<version>0.0.1-SNAPSHOT</version> <!-- 项目版本,SNAPSHOT表示开发版本 -->
<name>SpringBootPritical</name> <!-- 项目名称(显示用) -->
<description>SpringBootPritical</description> <!-- 项目描述 -->
<url/> <!-- 项目URL(可选) -->

<!-- 项目许可证信息(空标签表示未指定) -->
<licenses>
<license/>
</licenses>

<!-- 项目开发者信息(空标签表示未指定) -->
<developers>
<developer/>
</developers>

<!-- 版本控制系统信息(空标签表示未指定) -->
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>

<!-- 项目属性配置 -->
<properties>
<java.version>21</java.version> <!-- 指定Java版本为21 -->
</properties>

<!-- 项目依赖配置 -->
<dependencies>
<!--web开发的场景启动器,嵌入了 Tomcat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-satrter-web</artifactId>
</dependency>
<!-- Spring Security测试依赖,仅用于测试环境 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!--... 其他依赖 -->
</dependencies>

<!-- Spring Boot应用打包插件,项目构建配置 -->
<build>
<plugins>
<!-- Spring Boot Maven插件,用于打包和运行Spring Boot应用 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

这其实 pom.xml 文件里面有几个 Spring Boot 开发的步骤

创建项目,就是导入spring-boot-starter-parent继承

使用Spring Boot时,强烈推荐从spring-boot-starter-parent继承,因为这样就可以引入Spring Boot的预置配置

1
2
3
4
5
6
<!-- pom.xml -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
</parent>
  • 统一依赖版本:内置了所有 Spring Boot 依赖的版本号(称为 “BOM”,Bill of Materials),避免依赖冲突。
  • 简化配置:提供默认的插件配置(如编译版本、资源过滤等)。引入依赖时无需写version(除非需要覆盖默认版本)。

紧接着,我们引入了其他依赖,可发现无需指定版本号,因为引入的 <parent> 内已经指定了,只有我们自己引入的某些第三方jar包需要指定版本号。

导入场景

就是导入各种场景启动器

1
2
3
4
5
<!--web开发的场景启动器,嵌入了 Tomcat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-satrter-web</artifactId>
</dependency>

打包

1
2
3
4
5
6
7
8
9
10
<!-- Spring Boot应用打包插件,项目构建配置 -->
<build>
<plugins>
<!-- Spring Boot Maven插件,用于打包和运行Spring Boot应用 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

$ mvn clean package 把项目打成可执行的 jar 包

java -jar 包名.jar 启动项目

主程序启动类

1
2
3
4
5
6
7
8
9
10
11
12
package edu.software.ergoutree.springbootpritical;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// Spring Boot 项目的主入口程序,@SpringBootApplication为其核心注解,标记为启动类
@SpringBootApplication
public class SpringBootPriticalApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootPriticalApplication.class, args);
}
}

启动Spring Boot应用程序只需要一行代码加上一个注解@SpringBootApplication,该注解实际上又包含了:

  • @SpringBootConfiguration
    • @Configuration
  • @EnableAutoConfiguration
    • @AutoConfigurationPackage
  • @ComponentScan

这样一个注解就相当于启动了自动配置和自动扫描。

配置文件的异同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 8080
servlet:
context-path: /

spring:
application:
name: springboot-demo

logging:
level:
com.example.demo: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
1
2
3
4
5
6
7
spring.application.name=SpringBootPritical

server.port=8080
server.servlet.context-path=/

logging.level.edu.software.ergoutree.springbootpritical: DEBUG
logging.pattern.console="%d{yyyy-MM-dd HH:mm:ss} - %msg%n"

可见,YAML是一种层级格式,它和.properties很容易互相转换,它的优点是去掉了大量重复的前缀,并且更加易读。

而在配置文件中,我们经常使用如下的格式对某个key进行配置:

1
2
3
4
5
6
7
8
9
10
11
logging:
level:
com.example.demo: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" # 控制台日志格式

spring:
datasource:
url: ${DB_URL:jdbc:mysql://localhost:3306/app_db}
username: ${DB_USER:app_user}
password: ${DB_PASSWORD:app_pass}

${变量名:默认值}语法的核心逻辑

这种${DB_HOST:localhost}意思是,首先从环境变量查找DB_HOST,如果环境变量定义了,那么使用环境变量的值,否则,使用默认值localhost

这种语法的执行逻辑如下:

  1. 优先查找环境变量:Spring Boot 会首先检查操作系统环境变量中是否存在DB_HOST
  2. 其次查找系统属性:若环境变量不存在,会检查 Java 系统属性(如通过-DDB_HOST=xxx设置)
  3. 最后使用默认值:若前两者均不存在,则使用:, 后的默认值localhost

这使得我们在开发和部署时更加方便,因为开发时无需设定任何环境变量,直接使用默认值即本地数据库,而实际线上运行的时候,只需要传入环境变量即可,而且做到了配置与代码分离,避免敏感信息的直接显式暴露

Spring Boot 对环境变量的解析机制

  1. 变量解析顺序(优先级从高到低):
    • 命令行参数(如--db.host=xxx
    • 操作系统环境变量
    • application-{profile}.yml配置文件
    • application.yml配置文件
    • 代码中硬编码的默认值
  2. 复杂变量场景
    • 多层级变量:${APP_CONFIG.db.host}
    • 必选变量(无默认值):${REQUIRED_VAR}(若不存在则启动报错)
    • 组合变量:${DB_HOST}:${DB_PORT}

业务部分,以Controller为例子

实际上其他包也都是一回事,这里就拿 Controller 说了

使用 REST API 的 Controller 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package edu.software.ergoutree.springbootpritical.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

// 处理请求,映射 HTTP GET 请求到根路径 /。例如:访问 http://localhost:8080/ 时触发此方法
@GetMapping("/")
public String home(){
// 直接返回字符串 "Hello Spring Boot!",自动作为响应体返回给客户端。
return "Hello Spring Boot3!";
}

// 映射动态路径,例如:/hello/John、/hello/World。
// {name} 是路径变量,通过 @PathVariable 绑定到方法参数。
// 问 http://localhost:8080/hello/Alice → 返回 Hello, Alice!。
@GetMapping("/hello/{name}")
public String hello(@PathVariable String name) {
return "Hello, " + name + "!";
}
}

测试

在 test 文件夹下编写测试类就行,在这里会有一些特殊的注解

启动

Spring Boot自动启动了嵌入式Tomcat,当看到Started Application in xxx seconds时,Spring Boot应用启动成功。

现在,我们在浏览器输入localhost:8080就可以直接访问页面。那么问题来了:

前面我们定义的数据源、声明式事务、JdbcTemplate在哪创建的?怎么就可以直接注入到自己编写的UserService中呢?

这些自动创建的Bean就是Spring Boot的特色:AutoConfiguration。

当我们引入spring-boot-starter-jdbc时,启动时会自动扫描所有的XxxAutoConfiguration

  • DataSourceAutoConfiguration:自动创建一个DataSource,其中配置项从application.ymlspring.datasource读取;
  • DataSourceTransactionManagerAutoConfiguration:自动创建了一个基于JDBC的事务管理器;
  • JdbcTemplateAutoConfiguration:自动创建了一个JdbcTemplate

因此,我们自动得到了一个DataSource、一个DataSourceTransactionManager和一个JdbcTemplate

类似的,当我们引入spring-boot-starter-web时,自动创建了:

  • ServletWebServerFactoryAutoConfiguration:自动创建一个嵌入式Web服务器,默认是Tomcat;
  • DispatcherServletAutoConfiguration:自动创建一个DispatcherServlet
  • HttpEncodingAutoConfiguration:自动创建一个CharacterEncodingFilter
  • WebMvcAutoConfiguration:自动创建若干与MVC相关的Bean。

引入第三方pebble-spring-boot-starter时,自动创建了:

  • PebbleAutoConfiguration:自动创建了一个PebbleViewResolver

Spring Boot大量使用XxxAutoConfiguration来使得许多组件被自动化配置并创建,而这些创建过程又大量使用了Spring的Conditional功能。例如,我们观察JdbcTemplateAutoConfiguration,它的代码如下:

1
2
3
4
5
6
7
8
9
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {
}

当满足条件:

  • @ConditionalOnClass:在classpath中能找到DataSourceJdbcTemplate
  • @ConditionalOnSingleCandidate(DataSource.class):在当前Bean的定义中能找到唯一的DataSource

JdbcTemplateAutoConfiguration就会起作用。实际创建由导入的JdbcTemplateConfiguration完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {
@Bean
@Primary
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
JdbcProperties.Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());
if (template.getQueryTimeout() != null) {
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
}
return jdbcTemplate;
}
}

创建JdbcTemplate之前,要满足@ConditionalOnMissingBean(JdbcOperations.class),即不存在JdbcOperations的Bean。

可见,Spring Boot自动装配功能是通过自动扫描+条件装配实现的,这一套机制在默认情况下工作得很好,但是,如果我们要手动控制某个Bean的创建,就需要详细地了解Spring Boot自动创建的原理,很多时候还要跟踪XxxAutoConfiguration,以便设定条件使得某个Bean不会被自动创建。

使用开发者工具

在开发阶段,我们经常要修改代码,然后重启Spring Boot应用。经常手动停止再启动,比较麻烦。

Spring Boot提供了一个开发者工具,可以监控classpath路径上的文件。只要源码或配置文件发生修改,Spring Boot应用可以自动重启。在开发阶段,这个功能比较有用。

要使用这一开发者功能,我们只需添加如下依赖到pom.xml

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

然后,没有然后了。直接启动应用程序,然后试着修改源码,保存,观察日志输出,Spring Boot会自动重新加载。

默认配置下,针对/static/public/templates目录中的文件修改,不会自动重启,因为禁用缓存后,这些文件的修改可以实时更新。

简单打包 Spring Boot

普通的 Java 程序,使用 maven-shade-plugin就可以打包一个可执行的 jar 包

在Spring Boot应用中,打包更加简单,当然如果你只是打 jar 包,因为Spring Boot自带一个更简单的spring-boot-maven-plugin插件用来打包,我们只需要在pom.xml中加入以下配置

1
2
3
4
5
6
7
8
9
10
11
<project ...>
...
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

无需任何配置,Spring Boot的这款插件会自动定位应用程序的入口Class,我们执行Maven的打包命令即可打包:

1
$ mvn clean package

打包后我们在target目录下可以看到两个jar文件:

springboot-exec-jar项目为例

其中,springboot-exec-jar-1.0-SNAPSHOT.jar.original是Maven标准打包插件打的jar包,它只包含我们自己的Class,不包含依赖,而springboot-exec-jar-1.0-SNAPSHOT.jar是Spring Boot打包插件创建的包含依赖的jar,可以直接运行

这样,部署一个Spring Boot应用就非常简单,无需预装任何服务器,只需要上传jar包即可。

在打包的时候,因为打包后的Spring Boot应用不会被修改,因此,默认情况下,spring-boot-devtools这个依赖不会被打包进去。但是要注意,使用早期的Spring Boot版本时,需要配置一下才能排除spring-boot-devtools这个依赖

特性小结

  • 简化整合

    导入相关的场景,就拥有了相关的功能,也就是场景启动器

    Spring Boot官方默认支持很多 starter,amqp,aop,jdbc,jpa什么的都有,都叫spring-boot-starter

    第三方还要各种场景启动器的提供,命名为 *-spring-boot-starter

  • 简化开发

  • 简化配置

    application.properties:集中式管理配置,只需要修改这个文件就行,而且配置基本都有默认值

  • 简化部署

    都嫩打包为可执行的 jar 包,linux 服务器上有 java 环境就能运行

  • 简化运维

    修改配置(外部放一个 application.properties),监控应用,健康检查

Spring Boot Initializer

Spring Boot 创建项目的初始化向导,简化初始化项目

image-20250525141943983

下面就是选场景,选依赖

image-20250525142008987