怎么理解 Spring Boot 的约定优于配置 ?
在传统的 Spring 开发中,大家可能都有过这样的经历:项目还没开始写几行核心业务代码,就已经在各种配置文件中耗费了大量时间。比如,要配置数据库连接,不仅要在 XML 文件里编写冗长的数据源配置,还要处理事务管理、连接池配置等;搭建 Web 项目时,从配置 DispatcherServlet 到配置各种视图解析器,再到处理静态资源路径,每一步都需要小心翼翼地编写配置代码,稍有不慎就可能导致启动失败或功能异常。
二、什么是约定优于配置
“约定优于配置”(Convention over Configuration),也称作按约定编程,是一种软件设计范式,旨在减少软件开发人员需做出决定的数量,获得简单的好处,而又不失灵活性 。简单来说,就是框架通过一些默认的约定,帮我们预先设置好大部分通用的配置,开发者只需在少数不符合约定的情况下,才需要进行额外的配置工作。
举个生活中的例子,我们去餐厅吃饭,一般餐厅都会有默认的餐具摆放方式和点餐流程。如果没有特殊要求,我们就按照餐厅的 “约定” 来用餐,比如使用摆在桌上的筷子、勺子,在菜单上勾选菜品等。只有当我们有特殊需求,比如想要一次性手套代替筷子,或者需要额外的调料时,才需要向服务员提出 “配置” 要求。这就好比在 Spring Boot 开发中,框架已经为我们设定好了项目结构、依赖管理、配置文件加载等方面的约定,大部分情况下我们无需额外配置,只有在个别特殊场景下,才需要手动调整配置。
在 Spring Boot 中,“约定优于配置” 是其核心设计理念之一,它贯穿于整个框架的使用过程中。通过遵循这些约定,开发者能够快速搭建起一个功能完备的 Spring 应用,无需花费大量时间和精力在繁琐的配置工作上,从而将更多的注意力集中在业务逻辑的实现上,极大地提升了开发效率。
三、传统开发与 Spring Boot 对比
(一)传统 Spring 开发的配置痛点
在传统的 Spring 开发模式下,开发者往往要面对诸多繁杂的配置工作,这些配置工作不仅耗时费力,还容易出错,严重影响开发效率。
管理 jar 包依赖就是一项让人头疼的任务。在传统 Spring 项目中,我们需要手动引入项目所需的各种 jar 包,并且要确保各个 jar 包之间的版本兼容性 。一旦出现版本冲突,排查和解决问题就会变得异常困难。比如,在一个包含 Spring MVC、Spring Data JPA 和 Spring Security 等多个模块的项目中,需要引入大量相关的 jar 包,每个 jar 包可能又依赖其他的子 jar 包,稍有不慎就可能导致依赖冲突,像不同版本的 Spring 核心库之间的冲突,会引发各种难以调试的错误。
维护 web.xml 和 Dispatch - Servlet.xml 等配置文件也是一大痛点。在 web.xml 中,我们要配置 Servlet、Filter、Listener 等组件,定义它们的初始化参数、映射路径等 。例如,配置一个简单的 DispatcherServlet,就需要在 web.xml 中编写如下代码:
<servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc - servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>
而在 Dispatch - Servlet.xml(通常是 springmvc - servlet.xml)中,又要配置视图解析器、处理器映射器、处理器适配器等 Spring MVC 的核心组件 。配置视图解析器时,可能需要类似这样的配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB - INF/views/"/><property name="suffix" value=".jsp"/>
</bean>
随着项目规模的增大,这些配置文件会变得越来越臃肿,维护成本也越来越高。而且,不同的配置项之间可能存在复杂的依赖关系,修改一处配置可能会影响到其他部分的功能,这使得配置的管理变得非常困难。
(二)Spring Boot 如何简化配置
Spring Boot 通过引入自动配置和默认约定,彻底改变了这种繁琐的开发局面,让开发者能够从配置的泥潭中解脱出来,专注于业务逻辑的实现。
在依赖管理方面,Spring Boot 引入了 Starter 的概念 。Starter 是一组预定义的依赖集合,它将项目开发中常用的依赖进行了整合和封装。比如,当我们开发一个 Spring Boot Web 应用时,只需要在 pom.xml 文件中添加 spring-boot-starter-web 依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot 会自动管理该 Starter 所依赖的所有 jar 包版本,包括 Spring MVC、Tomcat(嵌入式 Servlet 容器)等相关依赖,无需我们手动去指定每个 jar 包的版本,大大减少了版本冲突的可能性 。
对于配置文件 ,Spring Boot 有一套默认的约定 。它默认加载 application.properties 或 application.yml 文件作为配置文件,并且对很多配置项都提供了默认值。例如,默认的 Web 服务器端口是 8080,如果我们没有在配置文件中指定端口号,应用就会使用这个默认端口启动 。在数据库连接配置方面,Spring Boot 也提供了默认的数据源配置,如果我们使用的是常见的数据库(如 MySQL、Oracle 等),只需要在配置文件中简单地配置数据库的连接信息,如用户名、密码、URL 等,Spring Boot 就会自动帮我们创建数据源和相关的数据库连接配置。例如,在 application.properties 中配置 MySQL 连接:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Spring Boot 会根据这些配置自动创建数据源,并将其注入到 Spring 容器中,供其他组件使用 .Spring Boot 还通过自动配置机制,根据项目中引入的依赖和配置文件,自动创建和配置 Spring 容器中的各种 Bean 。
例如,当我们引入了 spring-boot-starter-web 依赖后,Spring Boot 会自动配置 DispatcherServlet、视图解析器、处理器映射器等 Spring MVC 的核心组件,无需我们再像传统 Spring 开发那样在 XML 文件中进行繁琐的配置 。这一切都是基于 Spring Boot 的自动配置类和条件注解(如 @ConditionalOnClass、@ConditionalOnProperty 等)实现的,这些条件注解会根据类路径下是否存在某个类、配置文件中是否存在某个属性等条件来决定是否创建和配置某个 Bean。
(三)Starter 依赖机制
Starter 是 Spring Boot 的一项重要特性,它极大地简化了项目的依赖管理 。Spring Boot 将各种常见的应用场景封装成一个个的 Starter,每个 Starter 都是一组相关的依赖集合 。例如,spring-boot-starter-web是用于开发 Web 应用的 Starter,它包含了 Spring MVC、Tomcat(嵌入式 Servlet 容器)等相关依赖;spring-boot-starter-data-jpa是用于开发 JPA(Java Persistence API)数据访问层的 Starter,它包含了 Spring Data JPA、Hibernate 等相关依赖 。
当我们在项目中添加某个 Starter 依赖时,只需要在pom.xml(Maven 项目)或build.gradle(Gradle 项目)文件中添加相应的依赖坐标,Spring Boot 会自动管理该 Starter 所依赖的所有 jar 包版本,避免了手动管理依赖版本带来的麻烦 。例如,在 Maven 项目中添加spring-boot-starter-web依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
添加这个依赖后,Spring Boot 会自动引入 Spring MVC、Tomcat 等相关的 jar 包,并且会根据项目的需要自动配置好这些组件 。我们无需关心这些组件之间的依赖关系和版本兼容性,只需要专注于业务逻辑的开发 。这种方式不仅减少了配置工作量,还降低了因依赖冲突导致的问题发生概率 。
(四)自动装配机制
Spring Boot 的自动装配机制是 “约定优于配置” 理念的核心体现之一 。它通过扫描类路径下的META-INF/spring.factories文件,自动配置 Spring 容器中的 Bean 。
在每个 Spring Boot Starter 的 META-INF/spring.factories 文件中,定义了一系列的自动配置类 。例如,spring-boot-starter-web的spring.factories文件中定义了WebMvcAutoConfiguration等自动配置类,这些配置类负责创建和配置 Spring MVC 相关的 Bean,如DispatcherServlet、HandlerMapping、ViewResolver等 。当我们在项目中引入spring-boot-starter-web依赖后,Spring Boot 在启动时会扫描META-INF/spring.factories文件,找到与WebMvcAutoConfiguration相关的配置,并根据项目的实际情况(如是否存在相关的类、配置文件中的属性等)决定是否创建和配置这些 Bean 。
自动装配的核心原理是基于 Spring 的条件注解@ConditionalOnClass@ConditionalOnProperty等 。@ConditionalOnClass表示只有当类路径下存在某个类时,才会创建和配置相关的 Bean;@ConditionalOnProperty表示只有当配置文件中存在某个属性时,才会创建和配置相关的 Bean 。例如,WebMvcAutoConfiguration类上使用了@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })注解,这意味着只有当类路径下存在Servlet、DispatcherServlet和WebMvcConfigurer这三个类时,才会创建和配置 Spring MVC 相关的 Bean 。通过这种方式,Spring Boot 实现了根据项目的依赖和配置自动创建和配置 Bean,大大减少了开发者手动配置的工作量 。
四、优势
(一)提高开发效率
在传统的 Spring 开发中,开发者花费大量时间在各种配置文件的编写和调试上,往往项目还未开始核心业务开发,就已经被配置工作搞得疲惫不堪。而 Spring Boot 的 “约定优于配置” 理念,就像是为开发者打造了一条高速公路,让开发过程变得顺畅无阻。
以搭建一个简单的 Web 应用为例,在传统 Spring 开发中,光是配置 DispatcherServlet、视图解析器、各种过滤器等,就需要编写大量的 XML 配置代码,并且要确保各个配置项之间的逻辑关系正确无误。而在 Spring Boot 中,我们只需要引入spring-boot-starter-web依赖,Spring Boot 就会自动帮我们完成这些配置工作,开发者可以在短短几分钟内就搭建好一个基本的 Web 应用框架,迅速投入到业务逻辑的开发中。这种方式大大减少了配置时间,让开发效率得到了质的飞跃。
(二)增强代码的可维护性
统一的约定使得 Spring Boot 项目的结构和配置更加清晰、规范 。在一个遵循 Spring Boot 约定的项目中,团队成员可以很容易地找到他们需要的代码和配置文件。例如,按照约定的项目结构,控制器层的代码位于controller包下,服务层的代码位于service包下,数据访问层的代码位于repository包下,配置文件位于resources目录下。这种清晰的结构使得代码的可读性大大提高,当需要修改或扩展某个功能时,开发者可以快速定位到相关的代码和配置。
而且,由于大部分配置都是由框架自动完成的,开发者只需要关注自己的业务逻辑和少量的特殊配置,减少了配置文件中冗余和复杂的配置项,降低了配置出错的概率 。当项目规模逐渐增大时,这种优势更加明显,能够有效降低维护成本,提高项目的可维护性。
(三)促进团队协作
在团队开发中,一致的约定就像是一套通用的语言,让团队成员之间的沟通和协作变得更加顺畅 。如果每个成员都按照自己的方式进行配置和开发,那么在代码合并和集成时,很容易出现各种问题,比如配置冲突、依赖版本不一致等。而 Spring Boot 的 “约定优于配置”,让团队成员遵循相同的规则进行开发,减少了因配置差异而产生的问题 。
例如,在一个多人开发的 Spring Boot 项目中,大家都使用默认的配置文件格式和位置,按照约定的项目结构进行代码组织。这样,新加入的成员可以快速熟悉项目的结构和配置方式,融入团队开发中 。在进行代码审查时,也更容易理解其他成员的代码逻辑,提高了团队协作的效率,有利于项目的顺利推进
相关文章:

怎么理解 Spring Boot 的约定优于配置 ?
在传统的 Spring 开发中,大家可能都有过这样的经历:项目还没开始写几行核心业务代码,就已经在各种配置文件中耗费了大量时间。比如,要配置数据库连接,不仅要在 XML 文件里编写冗长的数据源配置,还要处理事务…...
Dify 是什么?Dify是一个开源的LLM应用开发平台,支持快速搭建生成式AI应用,具有RAG管道、Agent功能、模型集成等特点
首先,Dify是一个开源的LLM应用开发平台,支持快速搭建生成式AI应用,具有RAG管道、Agent功能、模型集成等特点75。根据搜索结果,网页6详细对比了多个RAG和AI开发框架,包括MaxKB、FastGPT、RagFlow、Anything-LLM等。其中…...

数据预处理都做什么,用什么工具
数据预处理是数据分析、数据挖掘和机器学习中的关键步骤,其目的是将原始数据转换为适合后续分析或建模的格式。以下是关于数据预处理的主要内容及常用工具的详细介绍: 一、数据预处理的主要任务 数据预处理的主要任务包括以下几个方面: 数据…...
windows蓝牙驱动开发-在蓝牙配置文件驱动程序中接受 L2CAP 连接
L2CAP 服务器配置文件驱动程序会响应来自远程设备的传入逻辑链接控制和适应协议 (L2CAP) 连接请求。 例如,PDA 的 L2CAP 服务器配置文件驱动程序将响应来自 PDA 的传入连接请求。 接收传入 L2CAP 连接请求 1. 若要接收来自特定 PSM 的任何远程设备的传入 L2CAP 连…...

【原理图PCB专题】自制汉字转码工具,适配Allgero 17版本 Skill
众所周知,在使用Skill来编写Allegro控制脚本时如果程序的源码里是汉字,那么有可能会出现乱码。比如像下图这样的程序: 在Allegro中运行如下图所示: 那么如果我们需要让他转成正常的中文字符,就需要将字符转成GBK编码 打开自制小软件:中文与GBK编码互转V1…...
欧拉公式在信号处理中的魔法:调幅信号的生成与频谱分析
欧拉公式在信号处理中的魔法:调幅信号的生成与频谱分析 “数学不是枯燥的符号,而是宇宙的诗歌。” 当我们用欧拉公式解开调幅信号的频谱密码时,仿佛看到电磁波在时空中跳动的频率之舞。这篇博客将带你亲手触摸信号处理中的数学之美。 一、当欧拉公式遇见调幅信号:一场数学与…...
如何在Ubuntu中切换多个PHP版本
在Ubuntu环境下实现PHP版本的灵活切换,是众多开发者与系统管理员的重要技能之一。下面,我们将深入探讨如何在Ubuntu系统中安装、配置及管理多个PHP版本,确保您的开发环境随心所欲地适应各类项目需求。 开始前的准备 确保您的Ubuntu系统保持…...
基于opencv的HOG+角点匹配教程
1. 引言 在计算机视觉任务中,特征匹配是目标识别、图像配准和物体跟踪的重要组成部分。本文介绍如何使用 HOG(Histogram of Oriented Gradients,方向梯度直方图) 和 角点检测(Corner Detection) 进行特征匹…...

Linux线程概念与线程操作
Linux线程概念与线程操作 线程概念 前面提到进程程序代码和数据进程结构体,在线程部分就需要进一步更新之前的认识 进程实际上承担分配系统资源的基本实体,而线程是进程中的一个执行分支,是操作系统调度的基本单位 此处需要注意࿰…...
AI软件栈:LLVM分析(五)
数据流分析是编译优化、代码生成的关键理论。其数学基础是离散数学中的半格(Semi-Lattice)和格。半格与格不仅是编译优化和代码生成的重要理论基础,也是程序分析、验证及自动化测试的系统理论基础。 文章目录 格、半格与不动点格、半格与不动点 半格是指针对二元组 < S …...

Git指南-从入门到精通
代码提交和同步命令 流程图如下: 第零步: 工作区与仓库保持一致第一步: 文件增删改,变为已修改状态第二步: git add ,变为已暂存状态 bash $ git status $ git add --all # 当前项目下的所有更改 $ git add . # 当前目录下的所有更改 $ g…...

Linux 文件系统挂载
系列文章目录 Linux内核学习 Linux 知识(1) Linux 知识(2) WSL Ubuntu QEMU 虚拟机 Linux 调试视频 PCIe 与 USB 的补充知识 vscode 使用说明 树莓派 4B 指南 设备驱动畅想 Linux内核子系统 Linux 文件系统挂载 文章目录 系列文章…...
Qt QSpinBox 总结
Qt5 QSpinBox 总结 1. 基本特性 用途:用于输入和调整整数值,支持通过上下箭头、键盘输入或编程方式修改值。 默认范围:0 到 99,可通过 setRange(min, max) 自定义。 步长控制:setSingleStep(step) 设置单步增减值&a…...
【OJ项目】深入剖析题目接口控制器:功能、实现与应用
《深入剖析题目接口控制器:功能、实现与应用》 一、引言 在在线编程平台或竞赛系统中,题目管理和提交是核心功能之一。QuestionController 类作为控制器层,承担着处理与题目相关的各种请求的重要职责,包括题目的增删改查、题目提…...
周考考题(学习自用)
1.查询student表中name叫张某的信息 select * from student where name张某; 2.写出char和varchar类型的区别 1)char存储固定长度的字符串,varchar存储可变长度的字符串(在实际长度的字符串上加上一个字节用于存储字符串长度)&a…...
【matlab】大小键盘对应的Kbname
matlab中可以通过Kbname来识别键盘上的键。在写范式的时候,遇到一个问题,我想用大键盘上排成一行的数字按键评分,比如 Kbname(1) 表示键盘上的数字1,但是这种写法只能识别小键盘上的数字,无法达到我的目的,…...

LabVIEW与小众设备集成
在LabVIEW开发中,当面临控制如布鲁克OPUS红外光谱仪这类小众专业设备的需求,而厂家虽然提供了配套软件,但由于系统中还需要控制其他设备且不能使用厂商的软件时,必须依赖特定方法通过LabVIEW实现设备的控制。开发过程中࿰…...
Android 系统Service流程
主要用到的源码文件 /frameworks/base/core/java/android/app/ContextImpl.java 和ams通信。 /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 初始化Service,.管理服务 ActiveServices对象mServices /frameworks/base/services/core/…...
Gartner预测2025年网络安全正在进入AI动荡时期:软件供应链和基础设施技术堆栈中毒将占针对企业使用的人工智能恶意攻击的 70% 以上
Gartner 预测,网络安全正在进入 AI 动荡时期。安全和风险管理领导者必须根据早期生成式 AI 部署的失败以及 AI 代理清洗来评估即将到来的 AI 进展。 主要发现 随着各大企业开展大量人工智能采用和开发项目,应用安全弱点的暴露程度不断提高,包…...
华为最新OD机试真题-最长子字符串的长度(一)-Python-OD统一考试(E卷)
最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,发现新题及时跟新。 题目描述: 给你一个字符串…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...

群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...