【SSM框架 | day24 Spring IOC 与 DI 核心原理深度解析】

本文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 基础配置

属性作用重点说明
idBean 的唯一标识不可重复,命名规范:小写字母开头,驼峰命名
classBean 的全类名必须是可实例化的类,包含完整包名
nameBean 的别名可多个别名,用逗号/分号/空格分隔
scopeBean 的作用范围默认 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,新增企业级特性
初始化时机懒加载预加载
功能扩展仅基础功能资源加载、事件机制、国际化等
实现类DefaultListableBeanFactoryClassPathXmlApplicationContext 等

3. @Autowired vs @Resource

@Autowired (Spring 注解):

  • 默认按类型匹配 → 按属性名匹配 → @Qualifier 指定

  • 支持 required 属性

  • 支持构造器注入

@Resource (JDK 注解):

  • 默认按名称匹配 → 按类型匹配

  • 无 required 属性

  • 不支持构造器注入

实际开发选择:

  • 仅用 Spring:@Autowired + @Qualifier

  • 跨框架兼容:@Resource

4. 单例 Bean 的线程安全问题

问题本质: 多线程并发访问共享的可变成员变量

解决方案:

  • 无状态 Bean 设计 (推荐): 不存储可变状态

  • ThreadLocal 封装状态: 线程隔离

  • 改为多例 Bean: 各自持有独立实例

  • 同步机制 (不推荐): 性能大幅下降

5. Spring IOC 容器初始化流程

核心阶段:

  1. 配置资源加载: 加载 XML/注解配置

  2. BeanDefinition 注册: 解析配置,注册 Bean 定义

  3. BeanFactory 初始化: 初始化核心组件

  4. Bean 实例化与依赖注入: 创建 Bean 并注入依赖

  5. Bean 初始化: 执行初始化逻辑,生成可用 Bean

底层原理: 基于反射、XML 解析、工厂模式实现

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值