当前位置: 代码网 > it编程>编程语言>Java > Spring核心思想之浅谈IoC容器与依赖倒置(DI)

Spring核心思想之浅谈IoC容器与依赖倒置(DI)

2025年01月21日 Java 我要评论
在日常开发中,我们总会面临一个问题:如何优雅地管理对象的创建和依赖? 你可能会写一堆代码来手动构造对象,但这种方式繁琐且难以维护。而当项目变得复杂,依赖链拉长,手动管理对象的方式很快就会捉襟见肘。这时

在日常开发中,我们总会面临一个问题:如何优雅地管理对象的创建和依赖? 你可能会写一堆代码来手动构造对象,但这种方式繁琐且难以维护。而当项目变得复杂,依赖链拉长,手动管理对象的方式很快就会捉襟见肘。

这时,spring 的 ioc 和 di 机制便是解放双手的利器,它让开发者专注于业务逻辑,容器则负责对象的创建与依赖管理。与此同时,mybatis 的动态代理更是省去了为每个接口手动实现类的麻烦,极大地提高了效率。

但你有没有想过,spring 是如何找到你的类并自动注入依赖的?mybatis 又是如何在没有实现类的情况下完成数据库操作的?如果你也有这些疑问,那恭喜你,今天的内容正是为你准备的!

一、控制反转 ioc

控制反转(inversion of control, ioc) 是一种设计思想。它强调将控制权从对象本身转移到容器中。服务中心(容器)负责管理各种资源(对象和依赖)。用户(对象)需要资源时,服务中心将资源提供给它。容器控制对象的创建、依赖注入和生命周期管理

在传统编程中,对象需要自己控制依赖的创建和管理;在 ioc 中,这些任务由容器负责。

容器根据 bean 的依赖关系,通过 di 注入所需的依赖。

二、依赖倒置 di

1. 详细概念

依赖注入(dependency injection, di) 是 ioc 的具体实现方式之一。

它通过注入的方式,将对象需要的依赖提供给它,而不是由对象自己去创建,spring会按需创建相应的对象,通过构造器、setter 方法或字段注入,把依赖传递给对象。

2. spring 中 di 的实现原理

  • 声明依赖:使用注解(@component@service@repository)将类标记为 spring 容器管理的 bean。
  • 注入依赖:spring 在启动时扫描类路径,自动检测依赖,并通过 @autowired 注解注入相应的bean。
  • 容器提供依赖:spring 容器会根据配置文件或注解,实例化对象并注入到需要的地方。

三、注册bean过程:以 spring+mybatis 为例

1. spring 是如何通过注解注册 bean 的

spring 通过 组件扫描(component scanning)注解识别 将类注册为 bean。

  • 注解识别:包括 @component@service@repository@controller 等。
  • 特定集成注解:如 mybatis 的 @mapper,它告诉 spring 将标注的接口注册为 bean,并交由 mybatis 动态代理生成实现类。

注册过程

  • spring 启动时会扫描指定的包路径。
  • 找到标注了这些注解的类或接口,并注册到 ioc 容器中,形成 bean 定义。

2. mybatis是如何动态生成 usermapper 的实现类的

usermapper 是接口,没有具体实现类。mybatis 会利用 @mapper 注解,结合 mapper 配置文件或注解中的 sql 语句,动态生成代理实现类

代理类生成过程

动态代理机制:mybatis 使用 jdk 动态代理,为每个 mapper 接口生成一个代理类。

invocationhandler:代理类拦截所有对接口方法的调用,将它们转发到 mybatis 的核心组件(如 sqlsession)执行 sql。

  • 执行 sql:
  • 根据方法名或注解,定位 sql 配置。
  • 使用 mybatis 的 executor 执行 sql 并返回结果。

3. @autowired 注入过程

  • 扫描 bean:spring 启动时,扫描 userserviceimplusermapper,分别标注了 @service@mapper,将它们注册为 bean
  • 识别依赖:spring 在注册 userserviceimpl bean 时,检测到其字段 usermapper 被标注了 @autowired,即是否依赖于其他 bean。

注入逻辑

找到目标 bean

  • 在 ioc 容器中,根据类型 usermapper 查找对应的 bean。
  • 如果找到多个匹配 bean,spring 会结合 bean 名称或 @qualifier 注解解决冲突。

依赖注入

  • spring 使用 java 反射机制为 usermapper 字段赋值。
  • 具体实现伪代码如下:
// 获取字段
field field = userserviceimpl.class.getdeclaredfield("usermapper");
// 使私有字段可访问
field.setaccessible(true);
// 将找到的 usermapper bean 注入到 userserviceimpl 实例
field.set(userserviceimplinstance, usermapperbean);

4. 总结:spring 与 mybatis 的结合

spring

  • 提供 ioc 容器,扫描 bean,处理依赖注入。
  • 通过反射将 usermapper 动态代理对象注入到 userserviceimpl

mybatis

  • 动态生成 usermapper 的代理实现类,负责将方法调用转化为 sql 查询。
  • 代理类中通过 invocationhandler 将方法调用委托给 mybatis 的 sql 执行器。

附加:代理类与 usermapper 实现类的差异

代理类

  • 动态生成,没有手写实现代码。
  • 通过拦截接口方法,转发到 mybatis 核心组件处理。

普通实现类

  • 静态定义,需手动实现每个方法的逻辑。

示例对比

// 动态代理生成的代理类示例
public class usermapperproxy implements usermapper {
    private final sqlsession sqlsession;
​
    public usermapperproxy(sqlsession sqlsession) {
        this.sqlsession = sqlsession;
    }
​
    @override
    public user findbyid(int id) {
        // 将方法调用转化为 mybatis 的 sql 执行
        return sqlsession.selectone("namespace.findbyid", id);
    }
}
​
// 普通实现类(手动实现)
public class usermapperimpl implements usermapper {
    @override
    public user findbyid(int id) {
        // 自己写逻辑,连接数据库,执行 sql
        return executesql("select * from user where id = ?", id);
    }
}

动态代理的优势在于:

  • 代码复用性高:只需定义接口和 sql,无需重复写实现类。
  • 与 sql 配置无缝对接:方便维护和管理 sql 语句。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com