2025.8.13~14 实习总结
第一阶段:理解 Spring 核心 —— IoC 和 AOP
1. IoC(控制反转)和 DI(依赖注入)
我们来用一个生活中的例子,通俗地解释一下 IoC(控制反转) 是什么:
举个例子:点汉堡
什么是控制反转?
❌ 以前的方式(没有 IoC):
你想吃一个汉堡,你会怎么做?
自己去买面包; 自己去买肉饼;
👉 这个过程就像传统编程:你要用某个功能(比如数据库连接、日志服务),你就得自己去“创建”和“管理”这些对象。
- 自己去买生菜、酱料;
- 自己回家把它们组装成一个汉堡。
public class Burger {Bread bread = new Bread();Meat meat = new Meat();Lettuce lettuce = new Lettuce();public void eat() {System.out.println("自己动手做汉堡,累死了...");}
}
问题来了:太麻烦!如果哪天肉涨价了,你得改代码;想换蔬菜?也得改代码。耦合度太高了!
✅ 现在的方式(用了 IoC):
你走进一家快餐店,对服务员说:“我要一个汉堡。”
然后呢?你不用关心面包哪来的、肉在哪煎的、菜洗没洗。服务员直接给你端上来一个做好的汉堡。
🍔 你只管吃,背后的“组装过程”有人(比如厨房)替你搞定。
这就是 控制反转(IoC) 的意思:
原本是你控制一切(主动创建对象),现在你把“控制权”交出去了,交给“别人”(比如 Spring 容器)来帮你准备所需的东西。
🔄 什么是“反转”?
这个“注入”的过程,就是 DI(依赖注入),它是实现 IoC 的一种方式。
- 正转:你自己 new 对象,自己管理依赖。
- 反转:你不再自己创建,而是告诉 Spring:“我需要一个 XX 服务”,Spring 主动给你“注入”进去。
🧩 总结一句话:
IoC 就像你把“做饭”的活儿外包给了餐厅,你只负责“吃饭”。
程序中,你不再自己 new 对象,而是由 Spring 容器帮你创建并“送上门”。
控制反转(Inversion of Control,简称 IoC)是一种设计原则,用于指导软件架构的设计。它的核心思想是将程序流程的控制权从应用代码转移到框架或容器中。传统上,应用程序代码直接负责创建对象和管理依赖关系,但在使用IoC原则时,这些职责被转交给了外部实体,通常是一个IoC容器。
什么是依赖注入?
我们继续用“吃汉堡”的例子,来超通俗地讲明白什么是依赖注入(DI)
回顾一下:你点了一个汉堡
以前你是自己买面包、买肉、洗菜、组装……太累了!
现在你走进快餐店,只说一句:“给我来个汉堡。”
过了一会儿,服务员直接端上来一个完整的汉堡。
你不需要知道这个汉堡是怎么做的,谁煎的肉,哪的面包——你只管吃。
那什么是“依赖注入”?
我们把“你”看作一个对象,“汉堡”是你“依赖”的东西。
在程序里:
- “你”是一个类(比如
Customer
)。 - “汉堡”是另一个类(比如
Burger
)。 - “你”想吃“汉堡”,也就是说,“你”依赖“汉堡”。
❌ 没有依赖注入时(自己做):
public class Customer {// 自己 new 一个汉堡Burger burger = new Burger();public void eat() {System.out.println("吃自己做的汉堡");}
}
👉 问题:你想换个“鸡肉汉堡”?得改代码!测试的时候想假装吃“素汉堡”?也得改代码!
✅ 有了依赖注入(别人给你做好):
ublic class Customer {// 不自己 new 了!只声明:我需要一个汉堡private Burger burger;// 通过构造函数,让“外面”把汉堡给我public Customer(Burger burger) {this.burger = burger;}public void eat() {System.out.println("吃别人给我的汉堡");}
}
🍔 谁给的?—— Spring 容器(比如快餐店厨房)
它提前做好了各种汉堡,当你需要时,自动把汉堡“注入”到你手里。
💉 什么是“注入”?
“注入”就是:别人把你要的东西,主动塞给你,你不用自己去找。
就像:
- 打针时,医生把药“注入”你身体;
- 在程序里,Spring 把“汉堡”、“数据库连接”、“日志服务”等,“注入”到你的类里。
✅ 举个真实场景:
你想用数据库,以前你得这样:
UserService userService = new UserService();
UserDao userDao = new UserDao(); // 自己 new
userService.setUserDao(userDao); // 手动设置
用了依赖注入后,你只需要:
@Autowired
private UserService userService;
👉 Spring 自动帮你把 UserService
找到,并“注入”进来,背后的 UserDao
它也自动给你准备好!
🎯 总结一句话:
依赖注入(DI)就是:你只管说“我要什么”,Spring 自动把东西送到你手上,不用你自己去找、自己造。
🧩 DI 和 IoC 的关系?
👉 所以:DI 是 IoC 的实现方式之一。
- IoC(控制反转):是思想,意思是“别自己动手,把控制权交给别人”。
- DI(依赖注入):是实现 IoC 的具体方法,就是“把依赖的东西注入给你”。
Spring 是如何通过配置(XML 或注解)管理对象的创建和依赖关系的?
Spring 框架的核心就是 IoC 容器,它负责创建对象、管理它们的生命周期,并自动处理对象之间的依赖关系。而 XML 配置 和 注解 就是告诉 Spring 容器“该创建哪些对象”、“它们之间有什么依赖”的两种方式。
Spring IoC 容器的工作流程
- 读取配置(XML 或 注解)
- 创建并管理对象(Bean)
- 自动注入依赖(DI)
- 提供对象给程序使用
📄 方式一:XML 配置(传统方式)
1. 写一个类(比如用户服务)
public class UserService {private UserDao userDao;// set 方法用于依赖注入public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void saveUser() {userDao.save();}
}
public class UserDao {public void save() {System.out.println("保存用户到数据库...");}
}
2. 写一个 applicationContext.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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 配置 UserDao 对象 --><bean id="userDao" class="com.example.UserDao" /><!-- 配置 UserService 对象,并注入 userDao --><bean id="userService" class="com.example.UserService"><property name="userDao" ref="userDao" /></bean></beans>
3. Spring 容器如何工作?
<bean class="com.example.UserDao"/>
→ Spring 看到这个,就会 new UserDao(),并把它存起来,叫userDao
。<bean class="UserService">
+<property name="userDao" ref="userDao"/>
→ Spring 创建UserService
,然后调用setUserDao(...)
,把前面创建的userDao
对象自动注入进去。
4. 使用
// 启动 Spring 容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 从容器中获取 UserService(它已经自动拥有 UserDao 了)
UserService userService = context.getBean("userService", UserService.class);userService.saveUser(); // 输出:保存用户到数据库...
✅ 总结 XML 方式:
- 所有对象和依赖都在 XML 里“写死”。
- Spring 容器读 XML → 创建对象 → 注入依赖。
🔖 方式二:注解配置(现代主流方式)
注解方式更简洁,代码即配置。
1. 先开启注解支持(可以是 XML 或 Java Config)
方式 A:用 XML 开启注解扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 开启组件扫描,告诉 Spring 去哪个包下找注解 --><context:component-scan base-package="com.example" /></beans>
方式 B:用 Java 配置类(@Configuration
)
@Configuration
@ComponentScan("com.example")
public class AppConfig {
}
2. 给类加上注解,告诉 Spring:“把我交给容器管理”
@Repository // 表示这是一个数据访问对象,Spring 会创建它
public class UserDao {public void save() {System.out.println("保存用户到数据库...");}
}
@Service // 表示这是一个业务服务,Spring 会创建它
public class UserService {@Autowired // 表示:Spring,请把 UserDao 对象自动注入给我private UserDao userDao;public void saveUser() {userDao.save();}
}
3. Spring 容器如何工作?
- 启动时,Spring 扫描
com.example
包; - 发现
@Repository
、@Service
等注解 → 自动创建这些类的实例; - 遇到
@Autowired
→ 自动查找匹配的 Bean(比如UserDao
),然后注入到字段中; - 所有依赖自动搞定!
4. 使用(和 XML 一样)
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 或 new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean(UserService.class);
userService.saveUser(); // 正常运行,依赖已注入
✅ 举个生活比喻
想象 Spring 是一家 智能餐厅:
- XML 配置:像一份详细的菜单和厨师手册,写明“哪个菜用什么料,怎么配”。
- 注解配置:像每道菜的标签:“这道菜要加葱(@Autowired)”、“这道是主菜(@Service)”。
- Spring 容器:就是厨房,根据菜单或标签,自动把菜做好、配好、端上来。
你作为顾客(业务代码),只管吃(用对象),不用管怎么做。
🎯 最终结论:
无论是 XML 还是注解,Spring 都是通过 读取配置 → 创建对象 → 自动注入依赖 的方式,实现了 IoC 和 DI。
注解更简洁现代,XML 更灵活可控,但底层原理一致。
学习内容:
- Bean 的定义与作用域(singleton、prototype)
- XML 配置 vs 注解配置(@Component、@Service、@Repository)
- @Autowired 注解的使用
- @Qualifier、@Primary 的使用
- @Configuration 和 @Bean 的使用