【Spring】IoC DI

devtools/2024/11/13 0:16:11/

控制反转(Inversion of Control,IoC)是 Spring 框架用来降低程序耦合度的一种解决方案。依赖注入(Dependency Injection,DI)是 IoC 的另一种说法。控制反转的核心思想是将对象的创建和管理权从程序本身转移给外部容器。进一步地,这个外部容器不仅负责创建对象,还会处理它们之间的依赖关系,这个建立依赖关系的过程称为依赖注入。

以吃面包为例,假设没有面包店时,你需要自己制作每种口味的面包,这意味着你必须掌握各种制作方法。每当有新口味出现,你都要学习新的制作技巧。然而,有了面包店后,你只需告诉店员你想要的口味,他们会为你提供现成的面包,无论口味如何新颖,对你都没有影响。在这个比喻中,Spring 容器就像面包店,而你则是程序本身。程序中的对象就像面包,其创建和管理由 Spring 容器负责,这就是控制反转的概念。这样,当类的实现发生变化时,程序本身无需修改(即你不受影响)。在 Spring 中,容器会将依赖的对象注入到调用者的成员变量中,并且建立对象与对象之间的依赖关系,从而实现依赖注入。

一、需求引入

这里以面包为实例,假设:业务层存在 BreadService 接口和 BreadServiceImpl 实现类,数据层存在 BreadDao 接口和 BreadDaoImpl 实现类。在BreadServiceImpl 实现类中,存在指向 BreadDao 具体实现类 BreadDaoImpl 的属性 breadDao,代码如下所示。

java">// 业务层
public class BreadServiceImpl implements BreadService {private BreadDao breadDao = new BreadDaoImpl();public void save() {breadDao.save();}
}// 数据层
public class BreadDaoImpl implements BreadDao {public void save() {}
}

现在由于出现了一种新口味的面包,引入了新的数据层代码实现类 NewBreadDaoImpl。如果此时希望获得新口味的面包,那么这个时候业务层的代码就会受到影响,需要重新指定属性 breadDao 的实现对象,代码如下所示。

java">// 业务层
public class BreadServiceImpl implements BreadService {private BreadDao breadDao = new NewBreadDaoImpl();public void save() {breadDao.save();}
}// 数据层
public class NewBreadDaoImpl implements BreadDao {public void save() {}
}

那么当这个项目部署上线后,每当出现一个新的面包口味,业务层的代码就要修改,项目需要重新测试部署。因此,为了解决这种耦合度高带来的不便,一种直接的思想是在使用对象时不主动在程序中使用 new 创建对象,而是转为由外部提供对象。这里的外部实际上就是 Spring 中的 IoC 容器。

二、技术实现

Spring 技术对 IoC 思想进行了实现,Spring 提供了一个容器,称为 IoC 容器,用来充当 IoC 思想中的“外部”。Spring 通过 IoC 容器来管理需要创建的对象。IoC 容器负责这些对象的创建、初始化等一系列工作,被创建或被管理的对象在 IoC 容器中统称为 Bean,比如面包案例中的servicedao 对象实例就可以称为 bean 对象。

三、具体使用

在使用 Spring 实现 IoC 的过程中,我们需要思考四个问题:

(1)利用 IoC 容器管理哪些 Bean 对象?

(2)如何将 Bean 对象告知 IoC 容器?

(3)如何获取 IoC 容器?

(4)如何获取由 IoC 容器管理的 Bean 对象?

在面包案例中,我们需要管理的 Bean 对象包括 ServiceDao。而 ServiceDao 信息则可通过配置告知 IoC 容器。至于 IoC 容器和 Bean 对象的获取则可以通过 Spring 提供的接口获得。这里通过 Idea 创建一个 Maven 项目,并展示控制反转和依赖注入的编码过程,项目代码目录如下所示。
在这里插入图片描述

  1. 导入Spring坐标

pom.xml 文件中编写 Spring 对应坐标,导入 Spring 包。这里的 Spring 版本使用的是 5.2.10.RELEASE。编写后等待 Spring 包下载,点击 Idea 右侧的 Maven 导航查看 DependenciesSpring 对应版本的包下载情况,确保下载完成。

java"><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency>
</dependencies>
  1. 定义 Bean 对象

这里同样以面包购买作为实例,在对应的 daoservice 包中定义需要的实现类。需要注意的是,由于 daoservice 之间存在依赖,因此,在 service 实现类中提供了一个 Setter 方法,用于帮助 IoC 容器实现依赖注入。另外,为了降低耦合,这里的 breadDao 属性指向的对象实例由 IoC 容器分配,从而实现控制反转。

java">// 业务层
public class BreadServiceImpl implements BreadService {private BreadDao breadDao;@Overridepublic void save() {breadDao.save();}public void setBreadDao(BreadDao breadDao) {this.breadDao = breadDao;}
}
java">// 数据层
public class BreadDaoImpl implements BreadDao {@Overridepublic void save() {System.out.println("hello");}
}
  1. 创建配置文件

resources 文件夹下面创建一个名为 applicationContext.xmlSpring 配置文件。具体地,右键 resources 文件夹,从 New 中选择 XML Configuration File 中的 Spring Config(若没有该选项,说明步骤1的依赖没下载成功)。在 applicationContext.xml 文件的 <beans> 中配置对应的 bean 对象。

java"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="breadDao" class="com.dao.impl.BreadDaoImpl"/><bean id="breadService" class="com.service.impl.BreadServiceImpl"><!-- 配置 dao 和 service 的依赖关系  --><property name="breadDao" ref="breadDao"></property></bean>
</beans>

注意:bean 标签表示配置的 bean 对象;id 用于唯一标识 bean 对象,该属性在同一个上下文中不能重复;class 属性用于指定 bean 对象的类型。另外,property 标签表示配置当前 bean 对象的属性;name 表示属性名;ref 表示指向的 bean对象 id

  1. 获取 IoC 容器

App 类的 main 方法中,通过 ClassPathXmlApplicationContext 类获取 IoC 容器。向ClassPathXmlApplicationContext 类构造方法传递需要的配置文件。

java">ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  1. 获取 bean 对象

在得到 IoC 容器后,通过 getBean 方法获取需要的 bean 对象。这里需要向 getBean 方法传递 bean 对象对应的 id 属性。

java">public class App {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BreadService breadService = (BreadService) ctx.getBean("breadService");breadService.save();}
}
ntext("applicationContext.xml");BreadService breadService = (BreadService) ctx.getBean("breadService");breadService.save();}
}

http://www.ppmy.cn/devtools/132921.html

相关文章

Qt的跨平台介绍

在实际开发中&#xff0c;Ubuntu 使用 Qt 编译并跨平台到 Windows 的场景并不算特别常见&#xff0c;但在一些特定情况下是非常有用的&#xff0c;尤其是在开发需要支持多个平台的跨平台应用时。这种方式的应用主要体现在以下几个方面&#xff1a; Linux 环境下开发 Windows 应…

人工智能--JupyterNoteBook 转换成 PDF

背景 我们希望将ipynb文件转换成pdf文件&#xff0c;需要如何处理&#xff1f; 10:24:52.677 [error] If you have not installed xelatex (TeX), you will need to do so before you can export to PDF. For further instructions, please see https://nbconvert.readthedoc…

如何用Neo4j做知识图谱

知识图谱概述 1.1 知识图谱的定义与重要性 知识图谱&#xff08;Knowledge Graph&#xff09;是一种用于表示和存储知识的结构化数据模型。它通过节点&#xff08;Node&#xff09;和边&#xff08;Edge&#xff09;来表示实体&#xff08;Entity&#xff09;及其之间的关系&…

MYSQL——事务管理

什么是事务 在数据库使用者角度&#xff0c;事务就是完成一个事件。例如一个员工信息数据库&#xff0c;要完成员工离职的事件&#xff0c;可能需要很多操作&#xff0c;比如删除员工基本信息以及员工在公司的表现&#xff0c;薪资水平等。而这一系列的操作就是为了完成员工离…

Python的函数

一、定义 函数的定义&#xff1a;实现【特定功能】的代码块。 形参&#xff1a;函数定义时的参数&#xff0c;没有实际意义 实参&#xff1a;函数调用/使用时的参数&#xff0c;有实际意义 函数的作用&#xff1a; 简化代码提高代码重用性便于维护和修改提高代码的可扩展性…

MyBatis几种SQL写法

目录 1. 批量操作:通过标签支持批量插入 2. 批量操作:通过标签支持批量更新 3. 批量操作&#xff1a;通过标签支持批量删除 4. 动态SQL 3. 多条件分支查询 4. SQL语句优化&#xff1a;使用标签避免多余的AND或OR关键字。 5. 注解方式使用MyBatis 6. 一对多 7. 多对一&…

Chrome与火狐哪个浏览器的隐私追踪功能更好

当今数字化时代&#xff0c;互联网用户越来越关注在线隐私保护。浏览器作为我们探索网络世界的重要工具&#xff0c;其隐私追踪功能的强弱直接影响到个人信息的安全。本文将对比Chrome和Firefox这两款流行的浏览器&#xff0c;在隐私追踪防护方面的表现&#xff0c;并探讨相关优…

水库汛限水位是什么?如何进行安全监测

汛限水位是指水库在汛期允许兴利蓄水的上限水位&#xff0c;也是水库汛期防洪调度时的起调水位。在汛期&#xff0c;为了确保水库大坝安全&#xff0c;防止洪水漫坝造成灾害&#xff0c;需要将水库水位控制在汛限水位以下。当水库水位超过汛限水位时&#xff0c;需要根据防洪调…