Spring IOC 容器和依赖注入(DI)

news/2025/11/3 13:31:06/文章来源:https://www.cnblogs.com/Lantz12/p/19186787

1、什么是 IOC?

IOC(Inversion of Control)控制反转,IOC的核心是将对象的创建和依赖关系的组装控制权从程序内部反转到外部容器。容器管理的是Bean的生命周期和依赖关系,而“对象之间的调用过程”通常是由业务逻辑本身决定的,容器并不管理“调用过程”

我们使用IOC的原因就是为了降低类之间的耦合度

1.1 Spring 实现 IOC 思想

  • Spring 提供了一个容器,称为IOC容器,用来充当IOC思想中的外部
  • IOC 容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在 IOC 容器中称为Bean

1.2 为什么要有 IOC?

目的:充分解耦

  • 使用 IOC 容器管理 bean(IOC)
  • 在 IOC 容器内将有依赖关系的 bean 进行关系绑定(DI)

最终效果:

  • 使用对象时不仅可以直接从 IOC 容器中获取,并且获取到的 bean 已经绑定了所有的依赖关系

2、IOC 底层原理

最主要的目的就是降低代码的耦合度,尽量地降到最低限度

  • xml 解析
  • 工厂模式
  • 反射

2.1 工厂模式和原始模式

原始模式

弊端:代码之间的耦合度高,UserService直接依赖于UserDao的具体实现,每一次调用UserService.execute()都要创建一次UserDao对象,这样会非常浪费jvm堆内存资源,

class UserService {execute() {UserDao userDao = new UserDao();userDao.add();}
}
class UserDao {add() {// CODE...}
}

2.1.1 工厂模式

相比于原始模式的优点:代码耦合度降低,在启动项目的时候,UserFactory会先创建一个UserDao对象存放到堆中,每次UserService需要调用UserDao.add()的时候,只需要在堆直接调用即可,可以集中管理对象的生命周期,避免重复创建对象

class UserService {execute() {UserDao userDao = UserFactory.getDao();userDao.add();}
}class UserFactory {private static UserDao userDao = new UserDao();public static UserDao getDao(){return userDao; // 返回同一个实例}
}class UserDao {add() {// CODE...}
}

2.1.2 xml 解析

ioc 过程

第一步:xml 配置文件,配置创建的对象

<bean id="UserDao" class="com.lantz.UserDao"></bean>

第二步:假设现在有了UserServiceUserDao类,创建工厂类

public class UserFactory {public static UserDao getDao(){String classValue = class属性值;Class clazz = Class.forName(classValue);return (UserDao)clazz.newInstance();}
}

至此,进一步降低耦合度

因此,IOC的底层基于 IOC容器完成,IOC 的底层思想就是创建工厂,利用工厂模式降低耦合度

3、Spring 提供给 IOC 的两个接口

BeanFactory
  • IOC容器基本实现,Spring 内部实现的接口,不提供给开发人员使用
  • 加载配置文件的时候不会创建对象,只有获取对象的时候(使用)才会创建对象

ApplicationContext(推荐)

  • BeanFactory接口的子接口,提供了更多的更强大的功能,一般由开发人员直接使用
  • 加载配置文件的时候就会把配置文件对象进行创建

4、DI 依赖注入

依赖注入的概念

DI(Dependency Injection)依赖注入:

  • 在容器中建立 bean 与 bean 之间的依赖关系的整个过程,即依赖注入

依赖注入指的是:当一个对象依赖于其他对象(或数据)时,由Spring 容器负责在运行的时候将这些依赖注入进去,而不是由对象本身去查找或创建

一句话:我要什么就由容器给,不用自己弄(new)

代码演示

数据层实现

public class BookDaoImpl implements BookDao{@Overridepublic void save() {System.out.println("book dao impl ...");}
}

业务层实现

public class BookServiceImpl implements BookService{private BookDao bookDao;@Overridepublic void save() {bookDao.save();}
}

图示:

整体图示:

img

IOC容器内

img

4.1 依赖注入方式

我们在向一个类传递数据的方式主要是两种:set方法、构造方法。依赖注入描述了在容器中建立了beanbean之间依赖关系的过程,bean运行需要的类型有:引用类型,简单类型(基本数据类型与string)

setter 注入

通过类的setter方法完成依赖注入

简单类型

<bean id="student" class="com.example.Student"><property name="name" value="Tom"/><property name="age" value="20"/>
</bean>
public class Student {private String name;private int age;// setter方法public void setName(String name) { this.name = name; }public void setAge(int age) { this.age = age; }
}

引用类型

<bean id="school" class="com.example.School"><property name="name" value="清华大学"/>
</bean><bean id="student" class="com.example.Student"><property name="name" value="Tom"/><property name="school" ref="school"/>
</bean>

ref用于注入引用类型(bean

public class Student {private String name;private School school;public void setName(String name) { this.name = name; }public void setSchool(School school) { this.school = school; }
}

构造器注入(推荐)

通过类的构造方法来完成依赖项注入(推荐)

简单类型

<bean id="student" class="com.example.Student"><constructor-arg name="name" value="Tom"/><constructor-arg name="age" value="20"/>
</bean>
public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}
}

引用类型

<bean id="school" class="com.example.School"><constructor-arg name="name" value="清华大学"/>
</bean><bean id="student" class="com.example.Student"><constructor-arg ref="school"/><constructor-arg value="Tom"/>
</bean>
public class Student {private School school;private String name;public Student(School school, String name) {this.school = school;this.name = name;}
}

5、依赖自动装配

5.1 什么自动装配

自动装配是 Spring 用来自动满足 bean 之间依赖关系的一种机制

5.2 自动装配的几种方式

含义 装配方式 说明 适用场景
no(默认) 不自动装配 所有依赖都需要手动使用 <property><constructor-arg> 指定 控制最严格,适合显式配置
byName(不推荐) 属性名 自动装配 Setter 方法 容器中存在 与属性名相同 ID 的 bean 时自动注入 当 bean 命名规范统一时很方便
byType(推荐) 类型 自动装配 Setter 方法 容器中存在 与属性类型匹配的 bean 时自动注入;若有多个同类型 bean 会报错 当同类型 bean 唯一时最常用
constructor 构造方法参数类型 自动装配 构造器 容器会根据构造函数参数类型自动选择匹配的 bean 进行注入 构造器注入场景
default 使用上级 <beans> 元素的默认设置 依赖 <beans default-autowire=""> <beans> 设置了默认装配方式,则该 bean 自动继承该策略 批量统一配置 bean 的装配策略

代码模拟

xml 配置

<bean id="bookDao" class="com.springbean.dao.impl.BookDaoImpl"/><bean id="bookService" class="com.springbean.service.impl.BookServiceImpl" autowire="byType"/>

bookDao 实现类

public class BookDaoImpl implements BookDao {private int bookName;public void setBookName(int bookName) {this.bookName = bookName;}@Overridepublic void save() {System.out.println("保存书籍...");}}

bookService 实现类

public class BookServiceImpl implements BookService {private BookDao bookDao;public BookServiceImpl() {System.out.println("service constructor...");}@Overridepublic void schedule() {System.out.println("预定了一本书...");bookDao.save();}public void setBookDao(BookDao bookDao) {System.out.println("service set ...");this.bookDao = bookDao;}}

测试函数

public class BookMain {public static void main(String[] args) {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");applicationContext.registerShutdownHook();BookService bookService = (BookService) applicationContext.getBean("bookService");bookService.schedule();}
}

BookServiceImpl 里有一个 BookDao 类型的属性

容器中存在一个 BookDaoImpl(类型匹配):

✅ 所以自动把 bookDao 注入到 bookService 里,就不要在测试函数添加一下这句了

BookDao bookDao = (BookDao) applicationContext.getBean("bookDao");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/954473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSP-S 2025 赛时总结

T1 花了约 40min,小失误。 看到题目第一眼没有想到贪心,是 dp。 好在最后想到了反悔贪心,及时止损。 T2 2h......,超级失误。 首先想了好久才想到可以先做一次 Kr 将 \(m\) 去掉。 然后想到很久没有前途的直接枚举…

MATLAB2025b安装教程

MATLAB是一款高级技术计算语言、交互式算法开发环境和现代数据分析工具,作为数学类科技应用软件中首屈一指的软件,非常适合用于机器学习、信号处理、控制设计、图像处理、通信、计算机视觉、计算金融以及机器人技术等…

2025年11月领先品牌认证机构排行榜:权威评测与选择指南

在当今竞争激烈的市场环境中,企业越来越需要通过权威认证来证明自身的市场地位和品牌价值。作为企业决策者,您可能正在寻找一家可靠的领先品牌认证机构,以提升品牌公信力、增强市场竞争力。这种需求通常出现在企业准…

leaflow部署openlist

很久之前就想写这个教程,但怕过于简单,但是看见群内有佬友部署openlist遇到权限的问题,所以写下了这个话题。 按着图片操作即可,选择完全模式,主要看init容器部分。 cpu和内存我分配的比较少,主打一个省钱。 如下…

2025年11月上海婚姻律师服务评测:行业标准与用户反馈全解析

在上海这座国际化大都市中,婚姻家庭关系的稳定对社会和谐具有重要意义。根据最新发布的婚姻家事法律服务行业白皮书显示,随着社会结构变化和民众法律意识提升,上海地区婚姻家事案件年增长率持续保持在10%以上。选择…

Comparable接口

1. Comparable接口概述 1.1 基本概念包位置: java.lang.Comparable 功能: 定义对象的自然排序规则 核心方法: compareTo(T o) 用途: 让对象支持排序操作(Arrays.sort、Collections.sort等)1.2 接口定义 public inter…

软件授权安全:如何筑牢防护壁垒

在当今数字化时代,软件授权安全是每个开发者都必须面对的重要问题。软件一旦被破解,不仅会导致经济损失,还可能损害品牌形象。本文将深入探讨软件授权的安全问题,并提供一些实用的防护策略,帮助开发者构建更加安全…

WinMTR Json版:支持 JSON 配置的内网路径追踪工具

WinMTR Json版:支持 JSON 配置的内网路径追踪工具🚀 软件特性开源可信赖,基于原生 WinMTR 改造 支持加载自定义 JSON 配置文件,无需 qqwry.dat 可显示主机名、管理 IP 及多个关联 IP 支持ipv4和ipv6📌 使用说明…

2025年11月遗嘱继承律所评价:多维数据与行业标准解析

随着社会财富积累和家庭结构多元化,遗嘱继承规划逐渐成为现代家庭关注的焦点。许多中老年人在面临财产分配时,往往因缺乏专业法律知识而陷入困惑;年轻家庭则为规避未来潜在纠纷,开始提前布局遗产传承方案。根据中国…

2025年11月遗嘱继承律所评测排行:专业能力客观评估

在人生的财富传承规划中,遗嘱继承是确保个人意愿得以实现、家庭和谐得以维系的重要法律保障。随着社会财富积累和人口老龄化趋势加剧,遗嘱继承法律服务需求呈现显著增长态势。根据司法部近年发布的律师行业年度报告数…

Java 时间日期类笔记

1. 核心时间日期API发展历程 1.1 各版本主要APIJava 8之前: Date、Calendar、SimpleDateFormat Java 8+: java.time包 (JSR-310) 推荐: 新项目统一使用java.time包2. Java 8+ 时间日期API (java.time) 2.1 核心类概览类…

Day11伪类选择器

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">…

写在十年之后

在博客园上断断续续写了有十年了,打算停更了;后续文章会写到公众号上,有需要的可以关注下,谢谢! #MySignature { background-color: #f8f8ee; border: solid 1px #e8e7d0; padding: 10px; margin-bottom: 10px; c…

检测php get变量是否存在以及是否有值

检测php get变量是否存在以及是否有值// 检测GET变量是否存在 if (isset($_GET[writer])) {// 变量存在$writer = $_GET[writer]; } else {// 变量不存在$writer = ; }// 检测GET变量是否存在且有值(不是空字符串、0、…

Python 文件操作

1. 创建文件 # open("文件名",读取模式,编码) , 需要手动关闭文件 fp = open("文件名",mode="a+",encoding="utf-8") # with open("文件名",读取模式,编码) , 自…

tp8-商城项目 命令合集

# 1. 解除框架版本锁定 composer remove topthink/framework --no-update # 2. 重装指定版本框架composer require topthink/framework:8.0.4 --no-plugins # 3. 安装微信支付SDKcomposer require wechatpay/wechatpay…

谭剑波day10

一 名从在翻译中的应用The notion that people have failed to detect the massive change is important.这是同位语从句翻译成也就是,同位语是可以调换顺序的,其他名从大都顺着翻译宾语从句:在介词,动词,及物动词…

2025年11月工装设计公司推荐排行:全国服务网络与项目经验深度解析

在选择工装设计公司时,企业决策者往往面临着诸多考量。无论是新办公空间的规划,还是商业场所的升级改造,都需要专业的设计团队提供全方位的解决方案。当前工装设计行业呈现出专业化、标准化的发展趋势,随着企业对工…

2025年11月上海遗产继承律师评测榜:基于真实数据的深度剖析

在当今社会,随着财富积累和家庭结构的多元化,遗产继承问题日益凸显其复杂性和重要性。上海作为中国的经济中心,涉及跨境资产、家族企业传承等高端继承案件频发,对律师的专业素养提出了更高要求。许多用户可能正面临…

JAVA中三个类的对比:String、StringBuffer和StringBuilder

在Java中,String、StringBuffer和StringBuilder都是用于处理字符串的类,但它们有不同的特性和适用场景。以下是它们的详细对比: 1. String 类 特性:不可变性:String对象一旦创建就不能被修改,底层使用char、底层…