“约定优于配置”(Convention over Configuration)是 Spring Boot 的核心设计哲学。它的含义是:框架默认提供一套合理的“约定”(默认行为),开发者只需遵循这些约定即可快速开发;只有当需要特殊行为时,才需要进行额外的“配置”。
Spring Boot 通过以下 四大核心机制 来实现这一理念:
1. 起步依赖 (Starters) —— 依赖管理的约定
问题:在传统 Spring 中,你需要手动寻找并引入几十个兼容的 jar 包(如 Spring MVC, Jackson, Tomcat, Validation API 等),且极易发生版本冲突。
Spring Boot 的约定:
它提供了一系列名为 spring-boot-starter-xxx 的依赖描述符。你只需要引入一个 Starter,它就自动引入了该场景下所有必需的、版本经过兼容性测试的依赖库。
- 例子:
- 你想开发 Web 应用?只需引入
spring-boot-starter-web。- 约定结果:自动包含 Spring MVC, Tomcat (内嵌), Jackson (JSON处理), Hibernate Validator 等。
- 你想操作 Redis?只需引入
spring-boot-starter-data-redis。- 约定结果:自动包含 Spring Data Redis, Lettuce (客户端), Jedis 等。
- 你想开发 Web 应用?只需引入
如何实现:
这些 Starter 本质上是 Maven/Gradle 的 POM 文件,内部定义了 <dependencies> 列表。父工程 spring-boot-starter-parent 统一管理了所有第三方库的版本号(BOM, Bill of Materials),确保版本兼容。
2. 自动配置 (Auto-Configuration) —— 行为逻辑的约定
这是 Spring Boot 最强大的魔法。它解决了“如何初始化 Bean”的问题。
问题:传统开发需要编写大量的 @Bean 方法或 XML 来配置数据源、事务管理器、MVC 视图解析器等。
Spring Boot 的约定:
“只要类路径下存在某个类,我就自动配置相关的 Bean。”
-
工作机制:
- Spring Boot 启动时,会扫描所有 jar 包下的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(Spring Boot 2.7/3.x 新机制) 或META-INF/spring.factories(旧机制) 文件。 - 这些文件中列出了所有的自动配置类(如
DataSourceAutoConfiguration,MvcAutoConfiguration)。 - 这些配置类上使用了一系列 条件注解 (
@Conditional) 来判断是否生效。
- Spring Boot 启动时,会扫描所有 jar 包下的
-
核心条件注解:
@ConditionalOnClass: 如果 classpath 下有指定类(如JdbcTemplate),则配置生效。@ConditionalOnMissingBean: 如果用户没有自定义该 Bean,则使用默认配置;如果用户自己定义了,则用户的配置优先(覆盖约定)。@ConditionalOnProperty: 如果配置文件中有特定属性(如spring.datasource.url),则生效。@ConditionalOnWebApplication: 如果是 Web 环境,则生效。
-
实战例子:数据库连接
- 约定:如果你引入了
spring-boot-starter-jdbc或spring-boot-starter-data-jpa,并且引入了 MySQL 驱动。 - 自动行为:Spring Boot 检测到这些类存在,自动创建一个
DataSourceBean,一个JdbcTemplateBean,甚至一个EntityManagerFactory。 - 默认值:它会尝试连接
localhost上的默认数据库。 - 按需配置:你只需要在
application.properties中修改 URL、用户名和密码,其他复杂的连接池配置(如 HikariCP)全部自动完成。
- 约定:如果你引入了
// 伪代码:DataSourceAutoConfiguration 的内部逻辑
@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {@Bean@ConditionalOnMissingBean // 只有用户没定义 DataSource 时,才创建这个public DataSource dataSource(DataSourceProperties properties) {// 使用 HikariCP (默认约定) 创建数据源HikariDataSource dataSource = new HikariDataSource();dataSource.setUrl(properties.getUrl());dataSource.setUsername(properties.getUsername());dataSource.setPassword(properties.getPassword());return dataSource;}
}
3. 内嵌服务器与目录结构约定 —— 部署与结构的约定
问题:传统 Java Web 需要安装外部 Tomcat,配置 web.xml,打 WAR 包,部署到特定目录。
Spring Boot 的约定:
- 内嵌服务器:应用即服务器。默认内嵌 Tomcat(也可选 Jetty/Undertow)。无需安装外部容器,直接
java -jar运行。 - 默认端口:Web 服务默认监听 8080 端口。
- 静态资源位置:默认去
src/main/resources/static或public目录下找 CSS/JS/图片,无需配置ResourceHandler。 - 模板引擎位置:默认去
src/main/resources/templates找 Thymeleaf 或 FreeMarker 模板。 - 配置文件位置:默认读取
src/main/resources/application.properties或application.yml。
如何打破约定:
如果觉得 8080 端口被占用,只需配置 server.port=8081;如果想改静态资源目录,配置 spring.web.resources.static-locations=classpath:/my-assets/。
4. 外部化配置的层级约定
Spring Boot 对配置文件的加载顺序也有严格的“约定”,允许在不同环境下灵活覆盖配置,而无需修改代码。
优先级从高到低(部分):
- 命令行参数 (
--server.port=9000) - SPRING_APPLICATION_JSON 中的属性
- ServletConfig 初始化参数
- ServletContext 初始化参数
- 环境变量 (
SPRING_DATASOURCE_URL) application-{profile}.properties(特定环境,如 prod)application.properties(通用配置)@PropertySource注解- 默认属性
约定体现:
开发者通常只维护一个默认的 application.yml。在开发环境直接运行;在生产环境,只需通过环境变量或命令行传入不同的 Profile (--spring.profiles.active=prod) 或覆盖特定的 Key,无需为每个环境重新打包或修改代码。
总结:开发者体验对比
| 场景 | 传统 Spring (配置优先) | Spring Boot (约定优先) |
|---|---|---|
| 引入依赖 | 手动查找并添加 Spring MVC, Tomcat, Jackson, Logging 等 10+ 个依赖,需核对版本。 | 添加 spring-boot-starter-web 1 个依赖。 |
| 配置数据源 | 定义 DataSource Bean, 配置连接池 (Hikari/DBCP), 配置 JdbcTemplate, 配置事务管理器。 | 引入 JDBC Starter + MySQL 驱动,在 properties 写 3 行 URL/用户/密码。其余全自动。 |
| 启动 Web | 安装 Tomcat, 配置 server.xml, 打 WAR 包, 部署。 | 代码内置 Tomcat, 打 JAR 包, java -jar 运行。默认端口 8080。 |
| 静态资源 | 配置 <mvc:resources mapping="..." location="..."/>。 |
把文件放入 static 文件夹,直接访问。 |
| 异常处理 | 配置 SimpleMappingExceptionResolver 或实现 HandlerExceptionResolver。 |
默认显示 Whitelabel Error 页面,或自定义 @ControllerAdvice 即可。 |
核心逻辑:
Spring Boot 通过 Starters 解决“用什么”,通过 Auto-Configuration 解决“怎么配”,通过 内嵌容器和目录规范 解决“怎么跑”。只有当你需要偏离这些默认的最佳实践时,才需要动手配置。这就是“约定优于配置”的完美体现。
