“约定大于配置”(Convention Over Configuration,简称 CoC)是一种软件开发哲学,它的核心思想是:通过预设的 “约定”(即通用的规则或默认行为)来减少不必要的配置工作,让开发者专注于业务逻辑而非基础设施。
背景
Spring Boot 的核心优势之一就是 “约定大于配置”(Convention Over Configuration),它通过自动化配置和 Starter 依赖机制,帮开发者省去了传统 Spring 项目中大量繁琐的配置工作,实现 “零配置启动”。以下是具体解释:
在 Spring Boot 之前,搭建一个完整的 Spring 项目需要:
手动配置 XML 或 Java Config
- 配置 DispatcherServlet、组件扫描路径、事务管理器、数据源等。
- 示例(XML 配置):
<context:component-scan base-package="com.example.demo" /> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mydb" /> </bean>
管理依赖地狱
- 需要精确匹配各组件版本(如 Spring、Hibernate、Jackson),版本冲突常见。
- 例如,引入 Spring MVC 时,需手动添加 servlet-api、jackson-databind 等依赖。
部署复杂
- 需要外部 Tomcat/Jetty 服务器,配置 Web.xml 或 Servlet 初始化类。
一、通俗类比:像 “住酒店” 而不是 “盖房子”
传统开发(配置地狱):
- 就像 “自己盖房子”:
你需要决定每一个细节 —— 墙刷什么颜色、插座装在哪里、马桶选什么型号…… 即使大部分需求和别人一样,也得从头设计。 - 示例:在传统 Spring 中,配置数据源需要写几十行 XML 或 Java Config,即使 90% 的项目配置都是相似的。
约定大于配置(Spring Boot):
- 就像 “住酒店”:
酒店已经按标准布置好房间(床、浴室、空调),你只需入住即可。如果有特殊需求(如加张床),再单独提出(少量配置)。 - 示例:Spring Boot 默认配置好数据源、Web 服务器等,你只需在
application.properties
中改几个参数(如数据库 URL)。
二、Spring Boot 中的具体体现
1. 目录结构约定
Spring Boot 默认遵循特定的目录结构,无需额外配置:
src/main/java
:Java 代码src/main/resources
:配置文件(application.properties、static/、templates/)src/test/java
:测试代码
src/main/java/ # Java 代码 com/example/demo/ # 主包路径 DemoApplication.java # 主应用类 src/main/resources/ # 资源文件 application.properties # 配置文件 static/ # 静态资源(CSS/JS/图片) templates/ # 模板文件(Thymeleaf) src/test/java/ # 测试代码
好处:无需配置组件扫描路径,Spring Boot 自动从 DemoApplication
所在包开始扫描。
2. 自动配置
Spring Boot 根据类路径中的依赖自动配置 Bean:
- 示例:
若引入spring-boot-starter-web
,则自动配置:- 嵌入式 Tomcat 服务器
- DispatcherServlet(Spring MVC 的核心)
- JSON 序列化 / 反序列化(Jackson)
- 默认错误处理页面
@RestController public class HelloController { @GetMapping("/") public String hello() { return "Hello, Spring Boot!"; } }
3. 默认属性值
Spring Boot 为几乎所有配置项提供默认值,你只需覆盖需要修改的部分。
# application.properties(只需配置与默认值不同的部分) server.port=8081 # 默认是 8080 spring.datasource.url=jdbc:mysql://localhost/mydb
4. Starter 依赖
Starter 是一组预定义的依赖集合,避免手动管理版本冲突。
<!-- 添加 Web 功能只需这一行 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
Starter 会自动引入:
- spring-webmvc
- tomcat-embed-core
- spring-boot-starter-json
- … 以及它们的兼容版本。
常用 Starter:
<!-- Web 应用 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JPA 数据访问 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
5.嵌入式服务器
Spring Boot 内置 Tomcat、Jetty 或 Undertow,无需部署 WAR 文件,直接通过 java -jar
运行。
# 只需在 application.properties 中指定端口 server.port=8081
三、为什么要遵循约定?
- 提高开发效率
- 减少重复配置,专注业务逻辑。
- 例如:传统 Spring 配置数据库需要 20 行代码,Spring Boot 只需 3 行(URL、用户名、密码)。
- 降低学习成本
- 新开发者无需记忆复杂配置,遵循约定即可。
- 例如:所有 Spring Boot 项目的启动方式都是
SpringApplication.run()
。
- 代码一致性
- 团队项目结构统一,便于协作和维护。
- 例如:所有组件都按约定放在
controller/
、service/
、repository/
包下。
- 减少错误
- 自动配置减少人为配置错误(如版本不兼容、Bean 命名冲突)。
四、何时需要打破约定?
约定并非强制,当默认行为无法满足需求时,可以:
- 覆盖默认配置
- 例如:修改默认端口、自定义错误处理器。
# application.properties server.port=8081
- 禁用自动配置
- 例如:禁用默认的数据源,使用自定义配置。
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) public class MyApp { ... }
- 自定义 Starter
- 为团队或项目创建专用的 Starter,封装特定业务的约定。
五、其他领域的 “约定大于配置”
- Maven 项目结构
src/main/java/ # 源代码 src/main/resources/ # 资源文件 src/test/java/ # 测试代码
无需配置编译器和测试运行器的路径。
- REST API 设计
约定 URL 路径和 HTTP 方法:
GET /users # 获取用户列表 POST /users # 创建用户 GET /users/{id} # 获取单个用户
减少文档和沟通成本。
- 数据库迁移工具(Flyway/Liquibase)
约定 SQL 文件命名规则:
V1__Initial_Setup.sql V2__Add_User_Table.sql
自动按版本号执行迁移。
六、总结
“约定大于配置” 是一种平衡效率与灵活性的哲学:
- 默认情况下:遵循约定,快速搭建项目;
- 需要定制时:通过少量配置覆盖默认行为。
Spring Boot 通过这种方式,将传统 Spring 项目的配置工作量从 “天” 级降低到 “分钟” 级,让开发者真正专注于 “写业务代码” 而非 “搭基础设施”。这也是 Spring Boot 成为 Java 企业级开发首选框架的核心原因之一。编辑分享