核心内容摘要
Dify 智能客服工作流:从零搭建高可用对话系统的实战指南
目录前言
Spring、Spring MVC 与 Spring Boot关系与区别
核心定位与功能
三者的依赖关系
实战场景举例图书管理系统
IoC控制反转Spring 核心思想
什么是 IoC
传统开发 vs IoC 开发耦合度对比1传统开发耦合度极高2IoC 开发彻底解耦
IoC 的核心优势
DI依赖注入IoC 的实现方式
什么是 DI
IoC 与 DI 的关系
DI 的实战体现
Spring 中 Bean 的存储与获取
Bean 的存储两种注解方式1类注解快速存储 Bean2方法注解 Bean灵活存储 Bean
Bean 的获取三种方式1通过类型获取推荐简洁2通过名称获取需强转3通过类型 名称获取解决同类型多个 Bean 冲突
上下文对比ApplicationContext vs BeanFactory
依赖注入的三种方式优缺点与实战
属性注入最常用简洁
构造方法注入Spring
X 推荐
Setter 注入Spring
X 推荐
三种注入方式对比表
解决多个同类型 Bean 的冲突
Primary指定默认 Bean
Qualifier指定 Bean 名称
Resource按名称注入JDK 提供
Bean 的命名规则
类注解Controller、Service 等的 Bean 命名
方法注解Bean的 Bean 命名
Spring 扫描路径确保 Bean 被正确识别
默认扫描路径
自定义扫描路径
常见面试题
总结高频考点
请谈谈 IoC 与 DI 的关系
三种依赖注入方式的优缺点
Autowired 与 Resource 的区别
Spring、Spring MVC、Spring Boot 的关系
BeanFactory 与 ApplicationContext 的区别
十、
总结前言在 Java 后端开发中Spring 生态无疑是绕不开的核心技术栈。
无论是初入职场的新手还是经验丰富的开发者理清 Spring、Spring MVC、Spring Boot 的关系掌握 IoC/DI 核心思想熟练运用 Bean 管理与依赖注入都是进阶路上的必备技能。
本文将结合实战案例从概念到实操全面拆解 Spring 生态的核心知识点帮你构建完整的知识体系。
Spring、Spring MVC 与 Spring Boot关系与区别很多开发者刚接触 Spring 生态时都会被这三个框架的关系搞晕。
其实可以用一个通俗的比喻理解Spring 是一个 “大家族”Spring MVC 是家族中负责 “Web 业务” 的成员而 Spring Boot 是家族的 “快速启动工具”。
核心定位与功能框架核心定位核心功能Spring轻量级、一站式企业级应用开发框架核心是 IoC 容器管理对象及依赖、AOP面向切面编程、事务管理、数据访问支持Spring MVC基于 Spring 的 Web 框架处理 HTTP 请求、URL 路由映射、参数接收、视图渲染、接口开发RESTfulSpring BootSpring 生态的 “脚手架”简化 Spring 应用开发自动配置、 Starter 依赖整合、内嵌服务器无需单独部署 Tomcat、简化配置文件
三者的依赖关系Spring 是基础Spring MVC 和 Spring Boot 都基于 Spring 核心IoC 容器、AOP 等实现无法脱离 Spring 独立存在。
Spring MVC 是 Spring 的子模块专门解决 Web 开发场景的问题相当于 Spring 生态中的 “Web 模块”。
Spring Boot 是 Spring 的 “封装增强”不提供新功能而是通过 “自动配置” 和 “依赖整合”简化 Spring Spring MVC 项目的搭建和配置。
实战场景举例图书管理系统// Spring Boot搭建项目框架自动配置 Tomcat、Spring 容器 SpringBootApplication public class BookApplication { public static void main(String[] args) { SpringApplication.run(BookApplication.class, args); } } // Spring MVC处理 Web 请求URL 映射、接口响应 RestController RequestMapping(/book) public class BookController { // SpringIoC 容器注入依赖BookService 对象由 Spring 管理 Autowired private BookService bookService; // Spring MVC处理 GET 请求返回 JSON 数据 RequestMapping(/getList) public ListBookInfo getList() { return bookService.getBookList(); // 调用业务逻辑 } } // Spring管理业务层 Bean处理核心逻辑 Service public class BookService { Autowired private BookDao bookDao; // 依赖注入数据访问层对象 public ListBookInfo getBookList() { ListBookInfo books bookDao.mockData(); // 业务处理转换状态为中文 for (BookInfo book : books) { book.setStatusCN(book.getStatus() 1 ? 可借阅 : 不可借阅); } return books; } }从代码中可以清晰看到Spring Boot 负责项目启动和自动配置Spring MVC 负责 Web 层的请求处理Spring 核心IoC/DI负责管理 Bean 及其依赖关系。
IoC控制反转Spring 核心思想
什么是 IoCIoCInversion of Control控制反转是 Spring 的核心思想本质是将对象的创建、管理权限从程序代码转移到 IoC 容器程序不再直接通过new关键字创建对象而是从容器中获取所需对象。
简单说传统开发是 “程序自己造对象”IoC 开发是 “容器送对象”。
传统开发 vs IoC 开发耦合度对比以 “造车” 为例直观感受两者的差异。
1传统开发耦合度极高传统开发中对象的创建是 “自上而下” 的上层对象依赖下层对象的创建修改底层会导致整个调用链修改// 传统造车Car 依赖 FrameworkFramework 依赖 BottomBottom 依赖 Tire public class TraditionalCarDemo { static class Car { private Framework framework; // Car 自己创建 Framework public Car() { this.framework new Framework(); System.out.println(Car init...); } } static class Framework { private Bottom bottom; // Framework 自己创建 Bottom public Framework() { this.bottom new Bottom(); System.out.println(Framework init...); } } static class Bottom { private Tire tire; // Bottom 自己创建 Tire public Bottom() { this.tire new Tire(); System.out.println(Bottom init...); } } static class Tire { private int size 17; public Tire() { System.out.println(Tire init: size size); } } public static void main(String[] args) { // 只需要创建 Car后续对象会被递归创建 new Car(); } }问题如果需要修改轮胎尺寸比如从 17 改为 20需要修改Tire、Bottom、Framework、Car四个类的构造函数耦合度极高可维护性差。
2IoC 开发彻底解耦IoC 开发中对象的创建是 “自下而上” 的上层对象通过 “注入” 获取下层对象不再自己创建// IoC 造车对象通过构造函数注入不再自己创建依赖 public class IocCarDemo { static class Car { private Framework framework; // 注入 Framework而非自己创建 public Car(Framework framework) { this.framework framework; System.out.println(Car init...); } } static class Framework { private Bottom bottom; // 注入 Bottom public Framework(Bottom bottom) { this.bottom bottom; System.out.println(Framework init...); } } static class Bottom { private Tire tire; // 注入 Tire public Bottom(Tire tire) { this.tire tire; System.out.println(Bottom init...); } } static class Tire { private int size; public Tire(int size) { this.size size; System.out.println(Tire init: size size); } } public static void main(String[] args) { // 先创建底层对象再注入到上层 Tire tire new Tire(
; Bottom bottom new Bottom(tire); Framework framework new Framework(bottom); Car car new Car(framework); } }优势修改轮胎尺寸时只需修改Tire的创建参数其他类无需改动彻底解耦。
IoC 的核心优势解耦消除对象间的直接依赖修改一个类不会影响其他类可维护性对象的创建、初始化统一由容器管理便于统一配置和修改可扩展性新增功能时只需新增 Bean 并配置依赖无需修改现有代码资源集中管理容器统一管理对象的生命周期创建、销毁避免资源泄漏。
DI依赖注入IoC 的实现方式
什么是 DIDIDependency Injection依赖注入是 IoC 思想的具体实现容器在创建 Bean 时自动将其依赖的其他 Bean 注入到当前 Bean 中无需程序手动获取。
简单说IoC 是 “让容器管对象” 的思想DI 是 “容器给对象送依赖” 的具体操作。
IoC 与 DI 的关系IoC 是 “目标”核心是反转对象的控制权DI 是 “手段”通过注入依赖的方式实现控制权反转。
比如“吃一顿好的” 是思想IoC“吃海底捞” 是具体实现DI。
DI 的实战体现在 Spring 中通过Autowired等注解实现 DI例如Service public class BookService { // 容器自动注入 BookDao 对象无需手动 new Autowired private BookDao bookDao; public ListBookInfo getBookList() { return bookDao.mockData(); // 直接使用注入的依赖 } }
Spring 中 Bean 的存储与获取Bean 是 Spring 容器管理的核心对象如 Service、Dao、Controller 等。
要让 Spring 管理 Bean需先 “存储” Bean再根据需求 “获取” Bean。
Bean 的存储两种注解方式1类注解快速存储 Bean适用于自定义类直接在类上添加注解Spring 会自动扫描并创建 Bean。
Spring 提供 5 种类注解对应不同的应用分层注解适用场景作用Controller控制层Web 层处理 HTTP 请求返回响应标识为 Web 层 BeanService业务逻辑层处理核心业务逻辑标识为业务层 BeanRepository数据访问层Dao 层操作数据库或数据存储标识为数据层 Bean还会自动处理数据库异常Component通用组件层无明确分层的通用 Bean如工具类是其他类注解的 “父注解”Configuration配置层项目配置类如数据源配置、Bean 配置标识为配置类 Bean使用示例// 控制层 Bean Controller public class UserController { public void sayHi() { System.out.println(Hi, UserController!); } } // 业务层 Bean Service public class UserService { public void sayHi() { System.out.println(Hi, UserService!); } } // 数据层 Bean Repository public class UserDao { public void sayHi() { System.out.println(Hi, UserDao!); } } // 配置类 Bean Configuration public class AppConfig { public void config() { System.out.println(App config...); } }2方法注解 Bean灵活存储 Bean适用于第三方类如User、DataSource或需要多个实例的场景通过方法返回 Bean 对象需配合类注解使用否则 Spring 无法扫描到。
使用示例// 配合 Component 类注解让 Bean 生效 Component public class BeanConfig { // 存储 User 实例Bean 名称默认是方法名 user1 Bean public User user1() { User user new User(); user.setName(张
; user.setAge(
; return user; } // 存储多个 User 实例通过 name 属性自定义 Bean 名称 Bean(name {user2, lisi}) public User user2() { User user new User(); user.setName(李
; user.setAge(
; return user; } }注意Bean 必须配合类注解如 Component、Configuration使用否则 Spring 无法识别若未指定 name 属性Bean 名称默认是方法名支持多个名称如name {user2, lisi}用逗号或数组分隔。
Bean 的获取三种方式获取 Bean 需先获取 Spring 上下文ApplicationContext再通过上下文获取 Bean。
常用三种方式1通过类型获取推荐简洁SpringBootApplication public class SpringIocDemo { public static void main(String[] args) { //
获取 Spring 上下文 ApplicationContext context SpringApplication.run(SpringIocDemo.class, args); //
通过类型获取 Bean UserController userController context.getBean(UserController.class); //
使用 Bean userController.sayHi(); // 输出Hi, UserController! } }2通过名称获取需强转// 通过 Bean 名称获取名称规则见下文 UserController userController (UserController) context.getBean(userController);3通过类型 名称获取解决同类型多个 Bean 冲突// 明确指定 Bean 名称和类型无需强转 User user context.getBean(user2, User.class); System.out.println(user); // 输出User(name李四, age
19)
上下文对比ApplicationContext vs BeanFactorySpring 容器有两个核心接口面试常考特性ApplicationContext推荐BeanFactory轻量继承关系继承 BeanFactory功能更全顶层接口提供基础功能初始化方式启动时一次性创建所有 Bean空间换时间按需创建 Bean用时才创建时间换空间额外功能支持国际化、资源访问、事件传播仅提供 Bean 存储和获取功能适用场景大部分应用Web 应用、Spring Boot资源受限场景如嵌入式设备
依赖注入的三种方式优缺点与实战Spring 提供三种依赖注入方式适用于不同场景需根据需求选择
属性注入最常用简洁通过Autowired直接标注字段容器自动注入依赖。
示例Controller public class UserController { // 直接注入 UserService Autowired private UserService userService; public void sayHi() { userService.sayHi(); // 输出Hi, UserService! } }优缺点优点代码简洁无需写构造函数或 Setter 方法缺点无法注入final修饰的字段final 字段需在构造时初始化仅支持 IoC 容器非 IoC 环境如单元测试无法使用容易出现空指针异常不符合 Java 规范字段私有化应通过构造或 Setter 访问。
构造方法注入Spring
X 推荐通过构造函数注入依赖Autowired可省略若只有一个构造函数。
示例Controller public class UserController { private final UserService userService; // 支持 final 字段 // 构造方法注入Autowired 可省略 public UserController(UserService userService) { this.userService userService; } public void sayHi() { userService.sayHi(); } }优缺点优点支持final字段确保依赖不可修改依赖在对象创建时初始化避免空指针异常通用性强符合 Java 规范换框架也能使用缺点依赖较多时构造函数参数过长代码繁琐。
Setter 注入Spring
X 推荐通过 Setter 方法注入依赖需在方法上添加Autowired。
示例Controller public class UserController { private UserService userService; // Setter 方法注入 Autowired public void setUserService(UserService userService) { this.userService userService; } public void sayHi() { userService.sayHi(); } }优缺点优点灵活性高可在对象创建后重新注入依赖符合 JavaBean 规范缺点无法注入final字段依赖可能被多次修改Setter 方法可被重复调用对象创建时依赖可能未初始化存在空指针风险。
三种注入方式对比表注入方式支持 final通用性代码简洁度依赖安全性属性注入不支持低高低构造方法注入支持高中高Setter 注入不支持中中中推荐用法依赖较少
个属性注入简洁依赖较多3 个以上构造方法注入安全需要动态修改依赖Setter 注入灵活。
解决多个同类型 Bean 的冲突当 Spring 容器中存在多个同类型 Bean 时使用Autowired会报错无法确定注入哪个需通过以下三种方式解决
Primary指定默认 Bean在多个同类型 Bean 中用Primary标注默认注入的 Bean。
示例Component public class BeanConfig { // 标注为默认 Bean Primary Bean(user
public User user1() { User user new User(); user.setName(张
; return user; } Bean(user
public User user2() { User user new User(); user.setName(李
; return user; } } // 注入时默认选择 Primary 标注的 user1 Controller public class UserController { Autowired private User user; // 注入的是 user1张三 }
Qualifier指定 Bean 名称配合Autowired使用通过value属性指定要注入的 Bean 名称。
示例Controller public class UserController { // 明确指定注入名称为 user2 的 Bean Autowired Qualifier(user
private User user; // 注入的是 user2李四 }注意Qualifier不能单独使用必须配合Autowired。
Resource按名称注入JDK 提供Resource是 JDK 自带的注解非 Spring 提供默认按名称注入可通过name属性指定 Bean 名称。
示例Controller public class UserController { // 按名称注入 user2 Resource(name user
private User user; // 注入的是 user2李四 }优势无需依赖 Spring 框架兼容性更强支持更多属性如name、type配置更灵活。
Bean 的命名规则Spring 对 Bean 的命名有明确约定避免手动配置时出现错误
类注解Controller、Service 等的 Bean 命名默认规则类名首字母小写其余驼峰命名如UserController→userController特殊情况类名前两个字母均为大写时保留原类名如UController→UController、AManager→AManager自定义名称通过注解的value属性指定如Controller(value myUserController)或简写Controller(myUserController)。
方法注解Bean的 Bean 命名默认规则Bean 名称 方法名如Bean public User user1()→ 名称为user1自定义名称通过name属性指定如Bean(name {u1, user1})。
Spring 扫描路径确保 Bean 被正确识别Spring 不会自动扫描所有包下的 Bean需满足扫描路径规则才能识别注解
默认扫描路径Spring Boot 中SpringBootApplication注解默认包含ComponentScan扫描路径为启动类所在包及其子包。
例如启动类BookApplication位于com.example.demo包下Spring 会自动扫描com.example.demo及所有子包如com.example.demo.controller、com.example.demo.service。
自定义扫描路径若 Bean 不在默认扫描路径下需通过ComponentScan手动指定// 扫描多个包com.example.demo 和 com.example.util ComponentScan({com.example.demo, com.example.util}) SpringBootApplication public class BookApplication { public static void main(String[] args) { SpringApplication.run(BookApplication.class, args); } }推荐实践将启动类放在项目根包下如com.example.demo所有业务代码放在子包中无需手动配置扫描路径。
常见面试题
总结高频考点
请谈谈 IoC 与 DI 的关系IoC控制反转是核心思想将对象的创建、管理权从程序转移到容器解决对象耦合问题DI依赖注入是 IoC 的实现方式容器在创建 Bean 时自动注入其依赖的其他 Bean关系IoC 是 “目标”DI 是 “手段”两者描述的是同一件事解耦只是角度不同IoC 从容器角度DI 从应用程序角度。
三种依赖注入方式的优缺点注入方式支持 final通用性代码简洁度依赖安全性属性注入不支持低高低构造方法注入支持高中高Setter 注入不支持中中中
Autowired 与 Resource 的区别对比维度AutowiredResource来源Spring 框架提供JDK 自带java.annotation注入方式默认按类型注入默认按名称注入支持属性仅支持required是否必须注入支持name、type等属性兼容性仅支持 Spring 容器支持所有 IoC 容器如 Spring、JBoss配合注解需配合Qualifier指定名称直接通过name指定名称
Spring、Spring MVC、Spring Boot 的关系Spring 是基础框架核心是 IoC 容器提供 AOP、事务管理等核心功能Spring MVC 是 Spring 的子模块专注于 Web 开发处理 HTTP 请求、路由映射等Spring Boot 是 Spring 的 “脚手架”通过自动配置、Starter 依赖简化项目搭建底层依赖 Spring 和 Spring MVC
总结Spring 是 “地基”Spring MVC 是 “Web 楼层”Spring Boot 是 “快速盖楼工具”。
BeanFactory 与 ApplicationContext 的区别特性ApplicationContext推荐BeanFactory轻量继承关系继承 BeanFactory功能更全顶层接口提供基础功能初始化方式启动时一次性创建所有 Bean空间换时间按需创建 Bean用时才创建时间换空间额外功能支持国际化、资源访问、事件传播仅提供 Bean 存储和获取功能适用场景大部分应用Web 应用、Spring Boot资源受限场景如嵌入式设备
十、
总结Spring 生态的核心是 IoC/DI通过容器管理 Bean 及其依赖实现代码解耦。
Spring MVC 专注于 Web 开发Spring Boot 简化配置三者分工明确、相辅相成。
掌握本文核心知识点理清 Spring、Spring MVC、Spring Boot 的关系理解 IoC/DI 的核心思想与实操熟练使用 Bean 的存储类注解、Bean与获取方式选择合适的依赖注入方式解决 Bean 冲突与扫描路径问题。