【Spring核心思想】IoC容器与依赖倒置(DI)

embedded/2024/12/28 22:03:07/

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


这时,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 的实现原理

  1. 声明依赖:使用注解(@Component@Service@Repository)将类标记为 Spring 容器管理的 Bean。

  2. 注入依赖:Spring 在启动时扫描类路径,自动检测依赖,并通过 @Autowired 注解注入相应的Bean。

  3. 容器提供依赖: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 语句,动态生成代理实现类

代理类生成过程

  1. 动态代理机制:MyBatis 使用 JDK 动态代理,为每个 Mapper 接口生成一个代理类。

  2. InvocationHandler:代理类拦截所有对接口方法的调用,将它们转发到 MyBatis 的核心组件(如 SqlSession)执行 SQL。

  3. 执行 SQL:

    • 根据方法名或注解,定位 SQL 配置。

    • 使用 MyBatis 的 Executor 执行 SQL 并返回结果。


3. @Autowired 注入过程

  1. 扫描 Bean:Spring 启动时,扫描 UserServiceImplUserMapper,分别标注了 @Service@Mapper,将它们注册为 Bean

  2. 识别依赖:Spring 在注册 UserServiceImpl Bean 时,检测到其字段 userMapper 被标注了 @Autowired,即是否依赖于其他 Bean。

注入逻辑

  1. 找到目标 Bean

    • 在 IoC 容器中,根据类型 UserMapper 查找对应的 Bean。

    • 如果找到多个匹配 Bean,Spring 会结合 Bean 名称或 @Qualifier 注解解决冲突。

  2. 依赖注入

    • Spring 使用 Java 反射机制为 userMapper 字段赋值。

    • 具体实现伪代码如下:

      java">// 获取字段
      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 核心组件处理。

  • 普通实现类

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

示例对比

java">// 动态代理生成的代理类示例
public class UserMapperProxy implements UserMapper {private final SqlSession sqlSession;
​public UserMapperProxy(SqlSession sqlSession) {this.sqlSession = sqlSession;}
​@Overridepublic User findById(int id) {// 将方法调用转化为 MyBatis 的 SQL 执行return sqlSession.selectOne("namespace.findById", id);}
}
​
// 普通实现类(手动实现)
public class UserMapperImpl implements UserMapper {@Overridepublic User findById(int id) {// 自己写逻辑,连接数据库,执行 SQLreturn executeSQL("SELECT * FROM user WHERE id = ?", id);}
}

动态代理的优势在于:

  1. 代码复用性高:只需定义接口和 SQL,无需重复写实现类。

  2. 与 SQL 配置无缝对接:方便维护和管理 SQL 语句。


http://www.ppmy.cn/embedded/149565.html

相关文章

项目文档-代码检查报告

在项目验收阶段会需要很多项目报告,这里记录一下代码检查报告的整理方式。 代码检查报告:项目需要记录每一个改动的代码类,并记录检查结果和修改情况,以及检查人员。 检查结果:是否检查通过 修改情况:暂无需…

用VBA自动更正错误的注释引用序号

将扫描pdf文件进行文字识别时,对带圈数字表示的注释引用和注释序号往往会将数字序号认错。例如下面的文件: 这个文件的段落十分有规律:每首诗的标题样式为标题3,标题下面的段落为诗的正文,下面有一个样式为标题4的段落…

怎么配置每一次重启服务器后,自动启动Tocmat

前言 宝子们,今天来给大家详细讲讲服务器如何配置每次重启后自动启动 Tomcat,让你的服务器应用始终保持在线状态,高效运行! windows版本 在 Windows 系统下,有两种常用的方法可以实现这个目标。 第一种方法是利用服…

SQL 实战:字符串处理函数 – 数据清洗与文本格式化

在数据分析和开发过程中,原始数据往往存在格式不统一、冗余字符等问题,直接影响查询和展示效果。SQL 提供了一系列强大的字符串处理函数,能够帮助开发者进行数据清洗和文本格式化操作,提高数据质量和查询效率。本文将通过多个实战…

Linux下Java通过JNI调用C++

以下为Demo流程 1.创建Java文件 public class HelloWord {// 声明本地方法public native void sayHello();static {// 加载本地库System.loadLibrary("hello");}public static void main(String[] args) {new HelloWord().sayHello();} } 2.编译生成.h头文件 在H…

5.npm包

文章目录 [TOC](文章目录) 3.npm与包3.1.包3.2.npm体验在项目中安装包的命令包管理配置文件一次性安装开发项目时安装的包如何从项目中卸载包devDependencies节点的作用解决下载包速度比较慢的问题nrm工具,利用其提供的终端命令,可以快速查看和切换下包的…

iPhone 17 :史诗级大改,120Hz 全面普及

资深果粉应该都听过一个说法:“iPhone 买单不买双”。这个“规律”似乎在iPhone 16上也得到了印证。 近段时间,各方消息都在指明一点:iPhone 16 只是大餐前的小菜,iPhone 17才是真正带来革命性提升的一代神机。下一代 iPhone 17&…

阿里云人工智能ACP(一)——人工智能与人工智能技术概述

一、人工智能概述 1. 人工智能的定义 人工智能 是利用数字计算机或者由数字计算机控制的机器,模拟、延伸和扩展人类的智能,感知环境、获取知识并使用知识获得最佳结果的理论、方法、技术和应用系统。 2. 人工智能的发展 3. 人工智能的分类 4. 人工智能…