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

2025-01-21 04:50

本文主要是介绍Spring核心思想之浅谈IoC容器与依赖倒置(DI),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Spring核心思想之浅谈IoC容器与依赖倒置(DI)》文章介绍了Spring的IoC和DI机制,以及MyBatis的动态代理,通过注解和反射,Spring能够自动管理对象的创建和依赖注入,而MyB...

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

这时,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 容器会根据配置文件或注解,实例化对象并注入到需要的地方。

三、注册BeNjLunVan过程:以 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 注http://www.chinasem.cn入到 userServiceImpl 实例
field.set(userServiceImplInstance, userMapperBean);

4. 总结:Spring 与 MyBatis 的结合

Spring

  • 提供 IoC 容器,扫描 Bean,处理依赖注入。
  • 通过反射将 UserMapper 动态代理对象注入到 UserServiceImpl

MyBaChina编程tis

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

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

代理类

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

普通实现类

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

示例对比

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

动态代理的优势在于:

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

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持China编程(www.chinasem.cn)。

这篇关于Spring核心思想之浅谈IoC容器与依赖倒置(DI)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153158

相关文章

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动