本文ssm使用的是配置开发的方式 实战使用较少 了解即可!
一、核心思想:IOC 与 DI
1. 传统开发的痛点与 Spring 解决方案
传统开发问题:
java
// 传统业务层代码:硬编码依赖,耦合度极高
public class BookServiceImpl implements BookService {
// 问题1:直接new Dao,业务层与Dao层强绑定
private BookDao bookDao = new BookDaoImpl();
// 问题2:若Dao实现类变更,必须修改业务层代码
}
后果: 维护成本高、扩展性差、测试困难
Spring 解决方案: 将对象创建权交给容器,依赖关系由容器自动绑定
2. IOC(控制反转)深度解析
"反转"的核心内容
-
传统开发: 程序主动控制对象创建和依赖管理
-
Spring 开发: 容器被动接收配置,主动创建对象、管理生命周期
IOC 容器本质
是一个工厂 + 注册表 + 依赖解析器的组合:
-
工厂: 根据配置创建 Bean 对象(反射实现)
-
注册表: 存储所有管理的 Bean
-
依赖解析器: 分析 Bean 间依赖,自动完成注入
核心价值
-
解耦: 业务层与数据层分离
-
可复用: Bean 由容器统一管理
-
可维护: 依赖变更只需修改配置
3. DI(依赖注入)深度解析
定义
容器在创建 Bean 时,自动将其依赖的其他 Bean 注入到属性中
实现前提
-
依赖方必须提供依赖属性的 setter 方法或构造器
-
被依赖方必须被 IOC 容器管理
IOC 与 DI 的关系
-
IOC 是思想: 反转对象创建权
-
DI 是手段: 通过注入依赖实现 IOC 的解耦目标
二、入门案例深度拆解
1. IOC 入门案例
核心步骤
步骤1:导入依赖
xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
步骤2:编写业务代码
java
// Dao接口
public interface BookDao {
void save();
}
// Dao实现类
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("BookDaoImpl.save():数据层保存图书");
}
}
// Service实现类(暂保留硬编码)
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
@Override
public void save() {
System.out.println("BookServiceImpl.save():业务层处理保存逻辑");
bookDao.save();
}
}
步骤3:Spring 配置
xml
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>
步骤4:从容器获取 Bean
java
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
2. DI 入门案例
核心步骤
步骤1:修改 Service 实现类
java
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void save() {
System.out.println("BookServiceImpl.save():业务层处理保存逻辑");
bookDao.save();
}
}
步骤2:修改配置文件
xml
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
三、IOC 核心配置:Bean 的精细化管理
1. Bean 基础配置
| 属性 | 作用 | 重点说明 |
|---|---|---|
| id | Bean 的唯一标识 | 不可重复,命名规范:小写字母开头,驼峰命名 |
| class | Bean 的全类名 | 必须是可实例化的类,包含完整包名 |
| name | Bean 的别名 | 可多个别名,用逗号/分号/空格分隔 |
| scope | Bean 的作用范围 | 默认 singleton,可选 prototype |
scope:单例 vs 多例
| 类型 | 核心特点 | 底层实现 | 适用场景 |
|---|---|---|---|
| singleton | 容器中仅1个Bean实例 | 容器初始化时创建 | Service、Dao、工具类 |
| prototype | 每次getBean()创建新实例 | 获取Bean时创建 | 实体类、域对象 |
验证代码:
java
BookDao dao1 = (BookDao) ctx.getBean("bookDao");
BookDao dao2 = (BookDao) ctx.getBean("bookDao");
System.out.println(dao1 == dao2); // singleton→true,prototype→false
2. Bean 实例化方式
(1)构造方法实例化(最常用)
底层原理: 容器通过反射调用无参构造器
要求: 必须有无参构造器
(2)静态工厂实例化(了解)
java
public class BookDaoFactory {
public static BookDao getBookDao() {
return new BookDaoImpl();
}
}
xml
<bean id="bookDao" class="com.itheima.factory.BookDaoFactory" factory-method="getBookDao"/>
(3)FactoryBean 实例化(实用)
java
public class BookDaoFactoryBean implements FactoryBean<BookDao> {
@Override
public BookDao getObject() throws Exception {
return new BookDaoImpl();
}
@Override
public Class<?> getObjectType() {
return BookDao.class;
}
}
xml
<bean id="bookDao" class="com.itheima.factory.BookDaoFactoryBean"/>
3. Bean 生命周期
完整流程
text
容器初始化 → 创建Bean实例 → 执行构造方法 → 属性注入 → 执行初始化方法 → Bean可用 → 容器关闭 → 执行销毁方法
生命周期控制方式
方式1:配置文件
java
public class BookDaoImpl implements BookDao {
public void init() {
System.out.println("初始化资源");
}
public void destroy() {
System.out.println("释放资源");
}
}
xml
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"
init-method="init" destroy-method="destroy"/>
方式2:实现接口(了解)
java
public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化资源");
}
@Override
public void destroy() throws Exception {
System.out.println("释放资源");
}
}
触发销毁方法
java
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook(); // JVM退出前自动关闭
// 或
ctx.close(); // 主动关闭
四、DI 核心配置:依赖注入的多种方式
1. 注入分类
-
简单类型: 基本类型 + String
-
引用类型: 其他 Bean
-
集合类型: 数组/List/Set/Map/Properties
2. Setter 注入(推荐)
引用类型注入
xml
<property name="bookDao" ref="bookDao"/>
简单类型注入
java
public class BookDaoImpl implements BookDao {
private String dbName;
private int dbPort;
public void setDbName(String dbName) {
this.dbName = dbName;
}
public void setDbPort(int dbPort) {
this.dbPort = dbPort;
}
}
xml
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="dbName" value="mysql"/>
<property name="dbPort" value="3306"/>
</bean>
3. 构造器注入(严谨,强制依赖)
混合注入示例
java
public class BookDaoImpl implements BookDao {
private String dbName;
private int dbPort;
private UserDao userDao;
public BookDaoImpl(String dbName, int dbPort, UserDao userDao) {
this.dbName = dbName;
this.dbPort = dbPort;
this.userDao = userDao;
}
}
xml
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg name="dbName" value="mysql"/>
<constructor-arg name="dbPort" value="3306"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
参数匹配方式
-
name(推荐): 按参数名匹配
-
index: 按参数下标匹配
-
type: 按参数类型匹配
4. 自动装配(简化配置)
自动装配方式
方式1:byType(推荐)
xml
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
方式2:byName
xml
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byName"/>
注意事项
-
仅支持引用类型注入
-
手动注入优先级 > 自动装配
5. 集合类型注入
数组/List 注入
xml
<property name="authors">
<array>
<value>鲁迅</value>
<value>老舍</value>
</array>
</property>
<property name="tags">
<list>
<value>小说</value>
<value>文学</value>
</list>
</property>
Map 注入
xml
<property name="config">
<map>
<entry key="encoding" value="UTF-8"/>
<entry key="timeout" value="3000"/>
</map>
</property>
Properties 注入
xml
<property name="props">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
五、核心总结
1. 思想层面
-
IOC: 反转对象创建权,解耦对象创建与使用
-
DI: 容器自动绑定 Bean 依赖,解耦 Bean 间依赖关系
-
最终目标: 高内聚、低耦合
2. 实操配置总结
| 核心功能 | 推荐配置方式 | 重点注意事项 |
|---|---|---|
| Bean 声明 | <bean id="" class=""/> | class 不能是接口,id 唯一 |
| 引用类型注入 | Setter 注入 (<property ref="">) | 必须提供 setter 方法 |
| 简单类型注入 | Setter 注入 (<property value="">) | 容器自动类型转换 |
| 强制依赖注入 | 构造器注入 (<constructor-arg>) | 适合必须的依赖属性 |
| 简化依赖配置 | 自动装配 (autowire="byType") | 确保容器中该类型 Bean 唯一 |
| Bean 作用范围 | 单例 (默认 singleton) | Service、Dao 用单例 |
六、高频面试题深度解析
1. Spring 如何解决 Bean 的循环依赖问题?
循环依赖定义: 两个或多个 Bean 互相依赖形成闭环
解决机制: 仅针对「单例 Bean + setter 注入/自动装配」场景,依赖「三级缓存」:
三级缓存:
-
一级缓存 (singletonObjects): 完全初始化完成的单例 Bean
-
二级缓存 (earlySingletonObjects): 提前暴露的半成品 Bean
-
三级缓存 (singletonFactories): Bean 工厂对象
无法解决的场景:
-
多例 Bean (prototype)
-
构造器注入
-
构造器注入混合场景
2. BeanFactory vs ApplicationContext
| 对比维度 | BeanFactory (基础容器) | ApplicationContext (高级容器) |
|---|---|---|
| 核心定位 | 基础 Bean 管理功能 | 继承 BeanFactory,新增企业级特性 |
| 初始化时机 | 懒加载 | 预加载 |
| 功能扩展 | 仅基础功能 | 资源加载、事件机制、国际化等 |
| 实现类 | DefaultListableBeanFactory | ClassPathXmlApplicationContext 等 |
3. @Autowired vs @Resource
@Autowired (Spring 注解):
-
默认按类型匹配 → 按属性名匹配 → @Qualifier 指定
-
支持 required 属性
-
支持构造器注入
@Resource (JDK 注解):
-
默认按名称匹配 → 按类型匹配
-
无 required 属性
-
不支持构造器注入
实际开发选择:
-
仅用 Spring:@Autowired + @Qualifier
-
跨框架兼容:@Resource
4. 单例 Bean 的线程安全问题
问题本质: 多线程并发访问共享的可变成员变量
解决方案:
-
无状态 Bean 设计 (推荐): 不存储可变状态
-
ThreadLocal 封装状态: 线程隔离
-
改为多例 Bean: 各自持有独立实例
-
同步机制 (不推荐): 性能大幅下降
5. Spring IOC 容器初始化流程
核心阶段:
-
配置资源加载: 加载 XML/注解配置
-
BeanDefinition 注册: 解析配置,注册 Bean 定义
-
BeanFactory 初始化: 初始化核心组件
-
Bean 实例化与依赖注入: 创建 Bean 并注入依赖
-
Bean 初始化: 执行初始化逻辑,生成可用 Bean
底层原理: 基于反射、XML 解析、工厂模式实现


被折叠的 条评论
为什么被折叠?



