云计算百科
云计算领域专业知识百科平台

通俗拆解Spring IoC/DI+三层调用全流程|苍穹外卖DAY2

前言

学习苍穹外卖第 2 天。今天不满足于 "代码能跑就行",我决定彻底搞清楚 Spring 最核心的两个概念:IoC(控制反转) 和 DI(依赖注入)。然后用一个真实的接口,把 Controller → Service → Mapper 的完整调用链走一遍。


一、传统方式:我自己招人干活

想象一下,没有 Spring 框架,我要开一家餐厅。我是老板(Service),需要一个切菜工(Mapper)来干活。

我只能自己去招人:

public class EmployeeServiceImpl {
// 我自己负责"找"和"创建"这个切菜工
private EmployeeMapper employeeMapper = new EmployeeMapperImpl();

public void login() {
employeeMapper.getByUsername(…); // 然后才能用他
}
}

这么做的问题:

  • 强依赖:必须精确知道去哪找切菜工(EmployeeMapperImpl),实现类变更,代码必须修改
  • 职责不清:既要写业务逻辑,又要负责对象创建,关注点混乱
  • 浪费资源:多个 Service 依赖同一个 Mapper,需重复创建对象,无法复用

二、Spring 方式:中介公司包办一切

Spring 框架开了一家强大的 "中介公司",学名叫做 IoC 容器(控制反转容器)。

核心概念

  • 控制反转(IoC):把 "创建对象、管理对象" 的控制权,从开发者代码交给 Spring 容器
  • 依赖注入(DI):组件需要的依赖对象,由容器自动装配进来,无需手动 new

所有 Bean(@Service/@Mapper/@Controller 等)在程序启动时被容器创建、管理;需要依赖时,容器自动注入,实现"别找我,我会找你"的设计哲学。


三、代码里的体现

@Service // 1. 注册为Bean,交给Spring管理
public class EmployeeServiceImpl {

@Autowired // 2. 声明依赖,容器自动注入
private EmployeeMapper employeeMapper; // 3. 无需手动创建,直接使用

public void login() {
employeeMapper.getByUsername(…); // 4. 直接调用
}
}

流程拆解

  • 扫描注册:Spring 启动,扫描 @Service/@Mapper,创建实例存入 IoC 容器
  • 依赖注入:创建 EmployeeServiceImpl 时,发现 @Autowired,从容器中取出 EmployeeMapper 注入
  • 使用对象:属性直接可用,全局单例,节约资源,便于管理

  • 四、为什么要用 IoC/DI?

    核心价值:解耦

    • 只依赖接口,不依赖具体实现类
    • 替换实现类时,业务代码无需修改
    • 统一管理对象生命周期,支持单例 / 多例等策略

    一句话总结

    • 控制反转(IoC):交出对象创建与管理的控制权
    • 依赖注入(DI):需要的依赖,框架自动送过来

    五、实战:启用 / 禁用员工完整调用链

    以启用 / 禁用员工功能为例,打通三层调用全流程。

    需求

    管理员点击禁用按钮,将员工账号状态改为停用(0)。

    • 前端请求:POST /admin/employee/status/0?id=3
    • 含义:ID=3 的员工状态设为 0(禁用)

    第一棒:Controller 层(接待员)

    负责接收请求、参数解析、调用 Service、返回统一结果

    // EmployeeController.java
    @PostMapping("/status/{status}")
    @ApiOperation("启用禁用员工账号")
    public Result startOrStop(@PathVariable Integer status, Long id) {
    log.info("启用禁用员工账号:{},{}", status, id);
    employeeService.startOrStop(status, id);
    return Result.success();
    }

    • 解析 URL 路径参数status与请求参数id
    • 不处理业务,直接转发给 Service
    • 封装 Result 返回前端

    第二棒:Service 层(业务处理层)

    负责业务逻辑编排、数据组装

    // EmployeeServiceImpl.java
    @Override
    public void startOrStop(Integer status, Long id) {
    // 组装要更新的数据
    Employee employee = Employee.builder()
    .status(status)
    .id(id)
    .updateTime(LocalDateTime.now())
    .updateUser(BaseContext.getCurrentId())
    .build();

    // 交给Mapper执行
    employeeMapper.update(employee);
    }

    踩坑记录

    // 错误写法:build()返回新对象未接收,传入空对象
    Employee employee = new Employee();
    Employee.builder().status(status).id(id).build();
    employeeMapper.update(employee); // SQL条件id=null

    ✅ 正确写法:用变量接收builder().build()返回的对象

    第三棒:Mapper 层(数据访问层)

    Mapper 接口

    // EmployeeMapper.java
    @Mapper
    public interface EmployeeMapper {
    void update(Employee employee);
    }

    XML SQL 映射

    EmployeeMapper.xml –>
    <update id="update" parameterType="Employee">
    update employee
    >
    ="name != null">name = #{name},>
    ="username != null">username = #{username},>
    ="password != null">password = #{password},>
    ="phone != null">phone = #{phone},>
    ="sex != null">sex = #{sex},>
    ="idNumber != null">id_number = #{idNumber}, != null">update_time = #{updateTime},>
    ="updateUser != null">update_user = #{updateUser}, null">status = #{status}, id = #{id}
    </update>

    MyBatis 执行流程

  • 根据接口 + 方法名匹配 SQL 模板
  • 解析>动态拼接 SQL
  • 替换#{}占位符,生成可执行 SQL
  • 执行并返回结果
  • 最终执行 SQL:

    update employee set status = 0, update_time = '2026-08-01…', update_user = 1 where id = 3

    结果返回链路

    数据库更新成功
    → Mapper 返回 void
    → Service 返回 void
    → Controller 封装 Result.success()
    → 前端收到 {"code": 1, "msg": "操作成功"}


    六、完整调用链路图

    前端 HTTP 请求

    Controller 层(接收请求、参数解析)
    | 数据形态:零散参数 → 传给Service

    Service 层(业务编排、对象组装)
    | 数据形态:零散参数 → Employee实体

    Mapper 层(SQL生成、数据操作)
    | 数据形态:实体 → 执行SQL

    数据库执行

    结果层层返回 → Controller封装 → 前端响应


    结尾

    今天终于搞懂了IoC/DI!看课的时候一直云里雾里感觉跟着敲完啥都没学到;打通了Controller→Service→Mapper三层调用全流程,终于是觉得学到东西了。

    如果你也在学 Spring,希望这篇博客能帮你把 IoC、DI 和三层调用链彻底吃透~ 欢迎评论区交流,一起进步!

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 通俗拆解Spring IoC/DI+三层调用全流程|苍穹外卖DAY2
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!