Spring Boot: 第一个 Spring Boot 应用
最后更新:2026-08-26
一个 @SpringBootApplication 注解就能启动整个应用——Spring Boot 的魔力背后是三个注解的精妙组合。
1. 你将学到
@SpringBootApplication注解拆解与组合原理- 主启动类
main()方法与SpringApplication.run()执行流程 application.propertiesvsapplication.yml配置文件格式- Spring Boot Banner 自定义与启动日志解读
- 运行第一个 "Hello OrderFlow" 接口
2. 一个新项目的真实故事
(1) 痛点:启动一个项目要配半天
Alice 回忆起刚入行时用传统 Spring MVC 的经历:创建一个项目需要配置 web.xml、applicationContext.xml、spring-mvc.xml,还要安装 Tomcat、配置数据源 JNDI。光是让项目跑起来就要花半天,更不用说调试启动顺序和 Bean 加载问题了。
(2) Spring Boot 的解法
Spring Boot 只需一个注解 + 一个 main 方法:
@SpringBootApplication
public class OrderFlowApplication {
public static void main(String[] args) {
SpringApplication.run(OrderFlowApplication.class, args);
}
}
(3) 收益
Alice 用 Spring Boot 创建 OrderFlow 项目,从零到第一个 API 响应只花了 5 分钟,无需任何 XML,无需外部容器,启动日志清晰可读。
3. @SpringBootApplication 注解拆解
(1) 三个注解的组合
@SpringBootApplication 是一个组合注解,等价于同时使用三个注解:
graph TB
A["@SpringBootApplication"] --> B["@SpringBootConfiguration"]
A --> C["@EnableAutoConfiguration"]
A --> D["@ComponentScan"]
B --> B1["Marks class as<br/>Configuration bean source"]
C --> C1["Triggers auto-configuration<br/>based on classpath"]
D --> D1["Scans components<br/>in same package tree"]
| 注解 | 作用 | 等价传统写法 |
|---|---|---|
@SpringBootConfiguration |
标记当前类是配置类 | @Configuration |
@EnableAutoConfiguration |
启用自动配置 | @EnableAutoConfiguration |
@ComponentScan |
组件扫描 | <context:component-scan> |
(2) @ComponentScan 的扫描规则
@ComponentScan 默认扫描主启动类所在包及其所有子包。
com.orderflow ← 主启动类所在包
├── OrderFlowApplication.java ← @SpringBootApplication
├── controller/ ← 被 @ComponentScan 扫描到
│ └── OrderController.java
├── service/ ← 被 @ComponentScan 扫描到
│ └── OrderService.java
└── repository/ ← 被 @ComponentScan 扫描到
└── OrderRepository.java
com.other ← ⚠️ 不在扫描范围内!
4. SpringApplication.run() 启动流程
(1) 启动时序
SpringApplication.run() 的执行过程是一个精心设计的流水线:
sequenceDiagram
participant Main as main()
participant SA as SpringApplication
participant Ctx as ApplicationContext
participant Bean as Beans
Main->>SA: new SpringApplication()
SA->>SA: infer Primary Sources
SA->>SA: check Web Application Type
SA->>SA: load Initializers & Listeners
Main->>SA: run(args)
SA->>SA: create Bootstrap Context
SA->>SA: prepare Environment
SA->>SA: print Banner
SA->>Ctx: create ApplicationContext
SA->>Ctx: prepare Context (register sources)
SA->>Ctx: refresh Context
Ctx->>Bean: instantiate Beans
Ctx->>Bean: auto-configure
SA->>SA: call Runners
SA->>Main: return ApplicationContext
(2) Web Application Type 判断
Spring Boot 自动判断应用类型:
| 条件 | 类型 | 使用的容器 |
|---|---|---|
classpath 有 spring-webmvc |
SERVLET | Tomcat / Jetty / Undertow |
classpath 有 spring-webflux 但无 spring-webmvc |
REACTIVE | Netty |
| 都没有 | NONE | 无内嵌容器 |
▶ 示例: 自定义 SpringApplication 启动
@SpringBootApplication
public class OrderFlowApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(OrderFlowApplication.class);
app.setBannerMode(Banner.Mode.CONSOLE);
app.setWebApplicationType(WebApplicationType.SERVLET);
app.run(args);
}
}
输出:
// 执行成功
5. 配置文件格式
(1) Properties vs YAML
Spring Boot 支持两种配置文件格式,功能等价但写法不同。
▶ 示例: application.properties 写法
server.port=8080
spring.application.name=orderflow-service
spring.datasource.url=jdbc:mysql://localhost:3306/orderflow
spring.datasource.username=root
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=update
输出:
// 执行成功
▶ 示例: application.yml 写法
server:
port: 8080
spring:
application:
name: orderflow-service
datasource:
url: jdbc:mysql://localhost:3306/orderflow
username: root
password: secret
jpa:
hibernate:
ddl-auto: update
输出:
配置文件已生效
| 维度 | Properties | YAML |
|---|---|---|
| 层级表达 | 用 . 分隔 |
用缩进表示层级 |
| 可读性 | 简单键值对,扁平 | 层级清晰,适合嵌套 |
| List 支持 | list[0]=a |
- a 更直观 |
| 重复前缀 | 需重复写 | 同层级共享前缀 |
| 解析性能 | 更快 | 略慢(需解析层级) |
| 优先级 | 相同 | 相同(同时存在时 properties 优先) |
(2) 常用配置项速查
| 配置项 | 默认值 | 说明 |
|---|---|---|
server.port |
8080 | 应用监听端口 |
spring.application.name |
— | 应用名称 |
server.servlet.context-path |
/ | 上下文路径 |
spring.main.banner-mode |
console | Banner 显示模式 |
spring.jpa.show-sql |
false | 是否打印 SQL |
logging.level.root |
INFO | 全局日志级别 |
6. Banner 自定义与启动日志
(1) 自定义 Banner
在 src/main/resources/banner.txt 中放置自定义 Banner,Spring Boot 启动时自动显示。
▶ 示例: OrderFlow 自定义 Banner
____ _ ____ __
/ ___| _ __ __ _| |_ ___ / ___|| | ___ _ __
| | | '_ \ / _` | __/ _ \ \___ \| |/ _ \| '_ \
| |___ | | | | (_| | || __/ ___) | | (_) | | | |
\____||_| |_|\__,_|\__\___| |____/|_|\___/|_| |_|
:: OrderFlow Service :: v${application.version:1.0.0}
:: Spring Boot ${spring-boot.version} ::
输出:
执行成功
(2) 启动日志解读
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | / / / /
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.2.5)
2024-01-15 10:00:01.123 INFO 12345 --- [main] c.o.OrderFlowApplication : Starting OrderFlowApplication
2024-01-15 10:00:03.456 INFO 12345 --- [main] o.s.b.w.e.t.TomcatWebServer : Tomcat initialized with port 8080 (http)
2024-01-15 10:00:04.789 INFO 12345 --- [main] o.s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories
2024-01-15 10:00:06.012 INFO 12345 --- [main] c.o.OrderFlowApplication : Started in 5.123 seconds
| 日志关键词 | 含义 |
|---|---|
Starting OrderFlowApplication |
应用开始启动 |
Tomcat initialized with port |
内嵌 Tomcat 启动 |
Bootstrapping Spring Data JPA |
自动配置 JPA 仓库 |
Started in X seconds |
启动完成,耗时 |
7. 运行第一个 Hello OrderFlow 接口
▶ 示例: Hello OrderFlow Controller
package com.orderflow.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class HelloController {
@GetMapping("/api/hello")
public Map<String, String> hello() {
return Map.of(
"message", "Hello, OrderFlow!",
"timestamp", java.time.Instant.now().toString()
);
}
}
输出:
HTTP 200 OK
Content-Type: application/json
{"status":"success","data":{}}
$ curl http://localhost:8080/api/hello
{"message":"Hello, OrderFlow!","timestamp":"2024-01-15T10:00:00Z"}
▶ 示例: 使用 @Value 注入配置
@RestController
public class HelloController {
@Value("${spring.application.name}")
private String appName;
@GetMapping("/api/info")
public Map<String, String> info() {
return Map.of(
"application", appName,
"javaVersion", System.getProperty("java.version")
);
}
}
输出:
// 执行成功
8. 综合示例:完整的 OrderFlow 启动配置
// src/main/java/com/orderflow/OrderFlowApplication.java
package com.orderflow;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OrderFlowApplication {
public static void main(String[] args) {
SpringApplication.run(OrderFlowApplication.class, args);
}
}
// src/main/java/com/orderflow/controller/OrderFlowController.java
package com.orderflow.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;
import java.util.Map;
@RestController
public class OrderFlowController {
@Value("${spring.application.name:orderflow}")
private String appName;
@GetMapping("/api/health")
public Map<String, Object> health() {
return Map.of(
"status", "UP",
"application", appName,
"timestamp", Instant.now()
);
}
}
# src/main/resources/application.yml
server:
port: 8080
spring:
application:
name: orderflow-service
$ curl http://localhost:8080/api/health
{"status":"UP","application":"orderflow-service","timestamp":"2024-01-15T10:00:00Z"}
❓ 常见问题
spring.main.banner-mode=off,或在代码中 app.setBannerMode(Banner.Mode.OFF)。server.port=8081,或找到占用端口的进程 kill 掉:lsof -i :8080(Linux/Mac)或 netstat -ano | findstr 8080(Windows)。--debug 模式查看详情。<mainClass> 配置;IDE 中直接运行含 main 方法的类;打包时 Spring Boot Maven Plugin 会自动识别。📖 小节
@SpringBootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan- 主启动类应放在根包下,确保组件扫描覆盖所有子包
SpringApplication.run()经历创建环境→创建上下文→刷新→实例化 Bean 的完整流程- YAML 和 Properties 功能等价,YAML 层级更清晰,Properties 解析更快
- 自定义 Banner 通过
banner.txt,启动日志可诊断启动问题
📝 作业
-
基础题(难度⭐):创建 Spring Boot 项目,自定义
banner.txt,将服务端口改为 9090,启动后验证/api/hello接口可访问。 -
进阶题(难度⭐⭐):使用
SpringApplicationBuilder替代SpringApplication.run(),关闭 Banner,设置日志级别为 DEBUG,并自定义一个/api/app-info接口返回应用名称和 Java 版本。 -
挑战题(难度⭐⭐⭐):实现一个
StartupListener实现ApplicationListener<ApplicationStartedEvent>,记录应用启动耗时并打印到日志,思考 Spring Boot 事件机制的设计意图。