news 2026/10/17 2:46:55

Spring 配置文件完全指南:从 XML 到 Spring Boot,一次搞懂

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring 配置文件完全指南:从 XML 到 Spring Boot,一次搞懂

Spring 系列目录

篇目标题状态

第 1 篇

Spring 入门与 Spring MVC 实战指南:从零理解 IoC 到 RESTful 图书管理

已发布

第 2 篇

告别new地狱:用大白话彻底搞懂 Spring IoC 与 DI

已发布

第 3 篇

Spring 配置文件完全指南:从 XML 到 Spring Boot,一次搞懂(本文)

当前阅读

第 4 篇

Spring Boot 自动配置原理与多环境 Profile 配置详解

规划中

第 5 篇

Spring 持久层实战:Spring Data JPA / MyBatis

规划中

第 6 篇

Spring Security:认证与授权入门

规划中

第 7 篇

Spring Cloud 微服务入门(进阶)

规划中

系列阅读建议:第 1 篇建立 Spring 全貌与 MVC 实战;第 2 篇吃透 IoC / DI / Bean;本文讲清 Bean 配置 与 应用属性配置 的分工与写法。建议按 1 → 2 → 3 顺序阅读,再进入自动配置与持久层。


文章目录

  • 系列文章目录
  • 引言
  • 一、核心概念:容器、Bean、依赖注入与配置
    • 1.1 用大白话理解
    • 1.2 两种配置,别搞混
    • 1.3 概念关系图
  • 二、常见配置方式
    • 2.1 XML配置(经典方式)
    • 2.2 Java配置(现代推荐)
  • 三、Spring Boot属性配置
    • application.properties 示例
    • application.yml 示例(等价写法)
    • 在代码中读取配置
  • 四、完整示例:通知服务小项目
    • 4.1 项目结构
    • 4.2 Java相关代码
    • 4.3 容器启动与依赖注入流程
    • 4.4 运行时的对象关系
    • 4.5 配置方式对比
  • 五、常见错误与排查建议
    • 5.1 Bean 找不到:NoSuchBeanDefinitionException
    • 5.2 循环依赖:BeanCurrentlyInCreationException
    • 5.3 属性绑定失败:配置值为 null 或默认值
    • 5.4 XML 与 Java 配置重复定义同一 Bean
    • 5.5 混淆 Bean 配置与属性配置
  • 六、总结

引言

我们写 Java 程序时,是不是经常遇到这样的问题:

  • 创建对象时,总要自己`new`,改一处就要改很多地方
  • 数据库连接地址写死在代码里,换环境就要重新编译
  • 类之间的依赖关系越来越乱,测试时 mock 一个对象都费劲

Spring 配置文件就是来解决这些问题的。它告诉 Spring 容器:要创建哪些对象(Bean)、它们之间怎么配合、应用运行时需要哪些参数。

本文适合有 Java 基础、刚接触 Spring 的开发者。读完后,你应该能区分「Bean 配置」和「应用属性配置」,并独立完成基础配置。


提示:以下是本篇文章正文内容,下面案例可供参考

一、核心概念:容器、Bean、依赖注入与配置

1.1 用大白话理解:

想象Spring容器是一个智能工厂:

1.我们给它一张【生产清单】(配置文件)

2.它按清单生产零件(创建Bean)

3.它还会自动把零件组装成成品(依赖注入)

Bean就是Spring 容器管理的对象。普通`new`出来的对象,Spring不管;通过配置注册的对象,Spring管它的创建、组装和生命周期。

依赖注入(DI)的意思是:A 需要B,我们不用自己new B()塞给A,Spring会自动把B注入给A。

配置文件就是那张【生产清单】。它回答三个问题:

1.2 两种配置,别搞混

这是新手最容易踩的坑:

Bean配置管【对象怎么造】;属性配置管【对象用什么参数运行】。两者配合使用,但职责不同。

1.3 概念关系图

图说明:NotificationService依赖MessageSender接口,具体实现可以是EmailSender或SmsSender。Spring 容器负责创建这些对象,并把sender注入到NotificationService中。换实现类时,只改配置,不改业务代码。

二、常见配置方式

2.1 XML配置(经典方式)

XML配置是Spring最早的方式,把所有Bean定义写在一个`.xml`文件里。优点是一目了然;缺点是配置多了文件会很长。

适用场景:老项目维护、需要集中查看所有Bean定义、团队习惯XML。

2.示例项目结构

otification-demo/

├── src/main/java/com/example/notification/

│ ├── MessageSender.java # 接口

│ ├── EmailSender.java # 实现类

│ ├── NotificationService.java # 业务类

│ └── Application.java # 启动类

└── src/main/resources/

└── applicationContext.xml # XML 配置

Java代码

package org.example.notification.service; // MessageSender.java public interface MessageSender { void send(String message); }
package org.example.notification.service.sender; import org.example.notification.service.MessageSender; import org.springframework.stereotype.Component; // EmailSender.java @Component public class EmailSender implements MessageSender { @Override public void send(String message) { System.out.println("[Email]" + message); } }
package org.example.notification.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; // NotificationService.java @Service public class NotificationService { // 字段注入(Spring Boot 组件扫描时使用) @Autowired private MessageSender sender; // Setter 注入(applicationContext.xml 的 <property> 需要) public void setSender(MessageSender sender) { this.sender = sender; } public void notifyUser(String content) { sender.send(content); } }
package org.example.notification; import org.example.notification.service.NotificationService; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; // Application.java @SpringBootApplication public class NotificationApplication { public static void main(String[] args) { SpringApplication.run(NotificationApplication.class, args); ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); NotificationService service = context.getBean("notificationService",NotificationService.class); service.notifyUser("您的订单已发货!"); } }

XML文件

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> &lt;!-- 注册 EmailSender 为 Bean,id 就是 Bean 的名称 --&gt; &lt;bean id="emailSender" class="org.example.notification.service.sender.EmailSender"/&gt; &lt;!-- 注册 NotificationService,并通过 property 注入 emailSender --&gt; &lt;bean id="notificationService" class="org.example.notification.service.NotificationService"&gt; &lt;property name="sender" ref="emailSender"/&gt; &lt;/bean&gt; </beans>

大白话解读:

  • <bean id="emailSender" ...>:告诉容器,创建一个 EmailSender 对象,名字叫 emailSender
  • <property name="sender" ref="emailSender"/>:创建 NotificationService 时,把名为 emailSender 的 Bean 塞给它的 sender 属性

这就是 字段注入。XML 里的 ref 指向另一个 Bean 的 id,容器会自动完成组装。

2.2 Java配置(现代推荐)

Java 配置用 @Configuration 和 @Bean 注解代替 XML。配置写在 Java 类里,有类型检查、IDE 自动补全,重构也更方便。

适用场景:新项目、需要复杂配置逻辑、团队偏好代码式配置。

配置类

package org.example.notification.config; import org.example.notification.service.MessageSender; import org.example.notification.service.NotificationService; import org.example.notification.service.sender.EmailSender; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration//标记这是一个配置类 public class AppConfig { @Bean//这个方法返回的对象会被注册为Bean public MessageSender emailSender(){ return new EmailSender(); } @Bean public NotificationService notificationService(MessageSender sender){ //方法参数sender 会自动注入容器中的MessageSender Bean NotificationService service = new NotificationService(); service.setSender(sender); return service; } }
package org.example.notification; import org.example.notification.config.AppConfig; import org.example.notification.service.NotificationService; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; // Application.java @SpringBootApplication public class NotificationApplication { public static void main(String[] args) { SpringApplication.run(NotificationApplication.class, args); //加载Java配置类,启动容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); NotificationService service = context.getBean(NotificationService.class); service.notifyUser("您的订单已发货!"); } }

大白话解读:

  • @Configuration:这个类是「配置说明书」
  • @Bean:这个方法生产一个 Bean,方法名默认是 Bean 名称(如 emailSender)
  • notificationService(MessageSender sender):Spring 看到参数类型,自动从容器里找一个 MessageSender 塞进来——这叫 方法注入

> 版本说明:Spring 4.3+ 起,如果 @Bean 方法只有一个构造器参数,也可以直接在 @Bean 方法里用构造器注入,写法更简洁。上面示例用 setter 是为了和 XML 版保持一致,便于对比。

三、Spring Boot属性配置

Spring Boot 大幅简化了Bean配置(自动配置+组件扫描),但应用运行参数仍然需要配置文件。

适用场景:几乎所有Spring Boot项目。

application.properties 示例
spring.application.name=notification # 服务端口 server.port=8080 自定义业务配置 notification.default-channel=email notification.retry-count=3
application.yml 示例(等价写法)
server: port: 8080 notification: default-channel: email retry-count: 3
在代码中读取配置
package org.example.notification.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "notification") public class NotificationProperties { private String defaultChannel = "email"; private int retryCount = 3; // getter/setter 省略 public String getDefaultChannel() { return defaultChannel; } public void setDefaultChannel(String defaultChannel) { this.defaultChannel = defaultChannel; } public int getRetryCount() { return retryCount; } public void setRetryCount(int retryCount) { this.retryCount = retryCount; } }
package org.example.notification.service; import org.example.notification.config.NotificationProperties; import org.springframework.stereotype.Service; @Service public class NotificationService { private final MessageSender sender; private final NotificationProperties properties; // 构造器注入:Spring 自动传入容器中的 MessageSender 和 NotificationProperties public NotificationService(MessageSender sender, NotificationProperties properties) { this.sender = sender; this.properties = properties; } public void notifyUser(String content) { System.out.println("渠道:" + properties.getDefaultChannel() + ",重试:" + properties.getRetryCount()); sender.send(content); } }

Spring Boot的Bean配置方式:

属性文件加载规则(SpringBoot 默认行为):

  1. 按优先级加载:application.properties / application.yml
  2. 支持多环境:application-dev.yml、application-prod.yml,通过 spring.profiles.active=dev 切换
  3. 默认位置:src/main/resources/,无需手动指定路径

四、完整示例:通知服务小项目

我们把上面的代码整合成一个可运行的Spring Boot项目。

4.1项目结构

notification/
├── pom.xml # Maven 构建配置
└── src/
├── main/
│ ├── java/org/example/notification/
│ │ ├── NotificationApplication.java # 启动类
│ │ ├── controller/
│ │ │ └── NotificationController.java # REST 接口层
│ │ ├── config/
│ │ │ ├── AppConfig.java # Java 配置(@Configuration + @Bean)
│ │ │ └── NotificationProperties.java # 应用属性绑定
│ │ ├── dto/
│ │ │ ├── SendNotificationRequest.java # 发送通知请求体
│ │ │ ├── SendNotificationResponse.java # 发送通知响应体
│ │ │ └── NotificationConfigResponse.java # 配置查询响应体
│ │ └── service/
│ │ ├── MessageSender.java # 消息发送接口
│ │ ├── NotificationService.java # 业务服务
│ │ └── sender/
│ │ └── EmailSender.java # 邮件发送实现
│ └── resources/
│ ├── application.yml # Spring Boot 属性配置
│ └── applicationContext.xml # XML Bean 配置(对比学习用)
└── test/
└── java/org/example/notification/
└── NotificationApplicationTests.java # 上下文加载测试

4.2 Java相关代码

启动类

package org.example.notification; import org.example.notification.service.NotificationService; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; @SpringBootApplication public class NotificationApplication { public static void main(String[] args) { SpringApplication.run(NotificationApplication.class, args); } }

给 EmailSender 加上组件注解

package org.example.notification.service.sender; import org.example.notification.service.MessageSender; import org.springframework.stereotype.Component; // EmailSender.java @Component public class EmailSender implements MessageSender { @Override public void send(String message) { System.out.println("[Email]" + message); } }

工具类

package org.example.notification.config; import org.example.notification.service.MessageSender; import org.example.notification.service.sender.EmailSender; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public MessageSender emailSender() { return new EmailSender(); } }
package org.example.notification.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "notification") public class NotificationProperties { private String defaultChannel = "email"; private int retryCount = 3; // getter/setter 省略 public String getDefaultChannel() { return defaultChannel; } public void setDefaultChannel(String defaultChannel) { this.defaultChannel = defaultChannel; } public int getRetryCount() { return retryCount; } public void setRetryCount(int retryCount) { this.retryCount = retryCount; } }

Service类

package org.example.notification.service; import org.example.notification.config.NotificationProperties; import org.springframework.stereotype.Service; @Service public class NotificationService { private final MessageSender sender; private final NotificationProperties properties; // 构造器注入:Spring 自动传入容器中的 MessageSender 和 NotificationProperties public NotificationService(MessageSender sender, NotificationProperties properties) { this.sender = sender; this.properties = properties; } public void notifyUser(String content) { System.out.println("渠道:" + properties.getDefaultChannel() + ",重试:" + properties.getRetryCount()); sender.send(content); } }
package org.example.notification.service; // MessageSender.java public interface MessageSender { void send(String message); }

DTO类

package org.example.notification.dto; public record NotificationConfigResponse( String defaultChannel, int retryCount ) { }
package org.example.notification.dto; public record SendNotificationRequest(String content) { }
package org.example.notification.dto; public record SendNotificationResponse( String message, String content, String channel, int retryCount ) { }
package org.example.notification.controller; import org.example.notification.config.NotificationProperties; import org.example.notification.dto.NotificationConfigResponse; import org.example.notification.dto.SendNotificationRequest; import org.example.notification.dto.SendNotificationResponse; import org.example.notification.service.NotificationService; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/notifications") public class NotificationController { private final NotificationService notificationService; private final NotificationProperties properties; public NotificationController(NotificationService notificationService, NotificationProperties properties) { this.notificationService = notificationService; this.properties = properties; } /** 发送通知 — POST /api/notifications */ @PostMapping("/send) @ResponseStatus(HttpStatus.CREATED) public SendNotificationResponse send(@RequestBody SendNotificationRequest request) { notificationService.notifyUser(request.content()); return new SendNotificationResponse( "通知已发送", request.content(), properties.getDefaultChannel(), properties.getRetryCount() ); } /** 查看当前通知配置 — GET /api/notifications/config */ @GetMapping("/config") public NotificationConfigResponse getConfig() { return new NotificationConfigResponse( properties.getDefaultChannel(), properties.getRetryCount() ); } }

配置文件

server: port: 8081 notification: default-channel: email retry-count: 3 spring: profiles: active: dev

测试:

POST http://localhost:8081/api/notifications/send

-H "Content-Type: application/json" \

-d "{\"content\":\"您的订单已发货!\"}"

4.3 容器启动与依赖注入流程

4.4 运行时的对象关系

4.5 配置方式对比

实际建议

  • Spring Boot 新项目:业务类用 @Service / @Component 扫描;第三方 Bean 用 @Configuration + @Bean;参数用 application.yml
  • 传统 Spring 项目:优先 Java 配置,XML 仅用于维护遗留代码
  • 不要混用过多方式:一个项目选主风格,避免同一 Bean 既在 XML 又在 Java 里定义

五、常见错误与排查建议

5.1 Bean 找不到:NoSuchBeanDefinitionException

原因:类没加 @Component / @Service,或不在组件扫描路径下。

排查:

  • 确认类在 @SpringBootApplication 所在包或其子包下
  • 或显式指定:@ComponentScan("com.example.notification")

2. 循环依赖:BeanCurrentlyInCreationException

原因:A 依赖 B,B 又依赖 A,容器无法决定先创建谁。

解决:改用构造器注入 + @Lazy,或重构设计打破循环。

3. 属性绑定失败:配置值为 null 或默认值

原因:

  • 键名写错(default-channel vs defaultChannel)
  • 缺少 getter/setter(@ConfigurationProperties 需要)
  • 未启用:@EnableConfigurationProperties(NotificationProperties.class)

排查:启动时加 --debug 查看绑定日志。

4. XML 与 Java 配置重复定义同一 Bean

原因:同一 Bean 被 @Bean 和 <bean> 各定义一次。

解决:只保留一种方式,删除重复定义。

5. 混淆 Bean 配置与属性配置

错误示例:在 application.yml 里写 myService.class=com.example.MyService(这不是标准做法)。

正确做法:Bean 用注解或 @Configuration;yml 只写运行参数。


六、总结

Spring 配置文件解决的核心问题是:谁来创建对象、对象之间如何协作、应用用什么参数运行。

三个要点:

  1. Bean 配置(XML / Java / 注解扫描)管对象的创建和依赖注入
  2. 属性配置(application.properties/yml)管端口、数据库 URL 等业务参数
  3. Spring Boot 通过自动配置和组件扫描,让大部分 Bean 无需手写配置

动手建议:

  1. 用本文的 notification-demo 结构,分别尝试 XML 和 Java 两种 Bean 配置方式
  2. 在 application.yml 里改 notification.default-channel,观察输出变化
  3. 故意写错一个 Bean 名称或配置键,对照「常见错误」章节练习排查

搞懂配置文件,你就掌握了 Spring 的「组装说明书」。后面学 AOP、事务、Web 开发,都是在容器已经帮你把对象准备好之后,往上面加能力——地基打牢,后面才稳。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 2:46:16

坚果云团队版管理最佳实践:从5人到500人的权限体系设计

文章目录一、权限管理的「规模墙」&#xff1a;为什么 5 人团队的方法在 50 人时失效&#xff1f;翻车案例一&#xff1a;创业公司的「权限噩梦」翻车案例二&#xff1a;设计公司的「权限过度」问题的本质二、5 人团队&#xff1a;轻量级权限方案2.1 核心原则&#xff1a;简单够…

作者头像 李华
网站建设 2026/10/17 2:46:11

SGM61630实战指南:重构Buck为反向Buck-Boost生成负电源轨

本文将以圣邦微电子的SGM61630芯片为例&#xff0c;系统性地为你拆解如何将一个标准的Buck&#xff08;降压&#xff09;变换器&#xff0c;重构为一个能够稳定输出负电压的反向Buck-Boost变换器。我们将从拓扑原理、电压电流应力分析出发&#xff0c;详细讲解关键辅助功能&…

作者头像 李华
网站建设 2026/10/17 2:45:34

商业 API 实现「换人跳舞视频」详细方案

商业 API 实现「换人跳舞视频」详细方案目标&#xff1a;输入「一段别人的跳舞视频&#xff08;动作来源&#xff09;」「一张目标人物图&#xff08;外观来源&#xff09;」&#xff0c;输出「目标人物跳同一支舞的视频」。 路线 A 的核心是用已托管的 Motion Control / 动作模…

作者头像 李华
网站建设 2026/10/17 2:45:34

脚本的效率探索和踩坑

常见脚本编写使用中效率很慢执行效率也不理想。萌生了自己打造一套的想法。执行效率问题因为是基于解释的和内置功能优化不足导致的。编写效率是还不够方便快捷。 先说执行效率问题那就把脚本编译成二进制可执行程序&#xff0c;把脚本语言翻译成编程语言在编译自然可解决。现在…

作者头像 李华
网站建设 2026/10/17 2:45:34

从诊断 42 分到 86 分:弘合星耀服务一家建材厂的 90 天全程复盘

先说结论这是一个把弘合星耀完整服务流程走完一遍的项目。从免费诊断、定制方案、签约启动&#xff0c;到九大智能体执行、每周周报复盘&#xff0c;90 天&#xff0c;客户在"弘合星耀 GEO 健康度诊断"里的评分从42 分提升到86 分&#xff1b;全网收录从不足 3 万条增…

作者头像 李华