Spring 核心概念之一 IoC

news2024/11/16 21:41:44

前言

欢迎来到本篇文章!通过上一篇什么是 Spring?为什么学它?的学习,我们知道了 Spring 的基本概念,知道什么是 Spring,以及为什么学习 Spring。今天,这篇就来说说 Spring 中的核心概念之一 IoC。

IoC 这个概念对于初学者来说还真不是很好理解,我就是那个理解不了的初学者。那时候,学起来很费解,只是迷迷糊糊知道了一些概念名词,控制反转,依赖注入。

现在,我重新梳理这些知识,尽量写清楚什么是 IoC 以及相关的知识,如有错误,敬请指正!好了废话不多说,进入正题!

什么是 IoC?什么是 Spring IoC 容器?

IoC(Inversion of Control),即控制反转,也被称为依赖注入(Dependency Injection,DI)

如果有对「依赖」不太明白的朋友,那么可以去看上一篇,在上一篇中,我们通过 Employee 和 Department 的例子解释了何为「依赖」

IoC 是一种定义对象之间依赖关系的过程。

在 Spring 没出现之前,当一个对象需要使用其他对象来完成某些操作,就需要我们自己去创建或查找这些依赖的对象。

现在,有了 Spring,我们的对象交给 Spring 管理,这些对象可以理解为存放在一个容器中的,这个容器就称为 Spring IoC容器。在 IoC 容器中,对象不再自己管理它们的依赖,而是通过构造方法参数、工厂方法的参数或者在对象创建后通过属性设置来定义它们的依赖关系

Spring 的 IoC 容器负责在创建对象时注入它们依赖的其他对象,也就是自动地把依赖的对象提供给需要它们的对象。这样一来,对象不再需要主动去查找或创建它们的依赖,而是由容器在创建对象时帮助它们完成依赖注入的过程。

控制反转的概念主要是与传统的直接构造(即 new 操作)来控制对象依赖的方式相反。传统方式中,一个对象通常会直接创建或查找它所依赖的其他对象,而在 IoC 中,对象将自身的控制权交给了容器,容器负责管理对象的创建和依赖注入,因此被称为「控制反转」。

初次见面 BeanFactory 和 ApplicationContext

在 Spring Framework 中,org.springframework.beansorg.springframework.context 包是 Spring IoC 容器的基础。

下面介绍两个新手村的伙伴给大家认识,BeanFactory 接口和它的子接口 ApplicationContext 接口。

BeanFactory 接口提供了一个高级配置机制,能够管理任何类型的对象。

对于它的子接口 ApplicationContext 来说,它的子接口增加了以下功能:

  • 更容易与 Spring AOP 特性集成

  • 消息资源处理(用于国际化)

  • 事件发布

  • 应用程序层特定上下文,例如 WebApplicationContext,用于 Web 应用程序。

简而言之,BeanFactory 提供配置框架和基本功能,而 ApplicationContext 添加了更多企业特定功能。

什么是 Bean?

在 Spring 中,构成应用程序骨干并由 Spring IoC 容器管理的对象称为 Bean。 Bean 是由 Spring IoC 容器实例化、组装和管理的对象。否则,Bean 只是我们应用程序中众多对象中的一个普通的对象而已。

Bean 及其相互依赖关系是反映在容器使用的配置元数据(Configuration Metadata)中的,这个配置元数据可以用 XML、Java 注解或 Java 代码表示。

提示:如果你和我一样比较喜欢深究这些英文单词的中文意思,现在的我给你个建议:

就是觉得没必要深究

比如说 Bean,中文是什么意思,你去找翻译,发现翻译是「豆」,还有类似 JavaBean,翻译是「Java 豆」,这些都是毫无意义的翻译,所以没必要知道它的中文意思是什么,Bean 就是 Bean,Bean 就是被 Spring IoC 容器管理的对象,这就是 Bean;JavaBean 则是只提供 setter 和 getter 的纯对象,本身没有任何业务逻辑,这就是 JavaBean。

容器是谁?

我们一直谈到「容器」,那么容器到底是什么呢?嘿嘿,容器马上就揭晓了!

实际上,Spring 的 IoC 容器就是由 org.springframework.context.ApplicationContext 接口来代表的。这个容器承担着实例化、配置和组装Bean的责任。

容器通过读取配置元数据来了解如何创建、配置和组装对象,同时也允许我们描述应用程序中各个对象之间的复杂依赖关系。目前从本系列的角度来看,我们会使用传统的 XML 方式来定义配置元数据,这是我们需要学习和了解的,后续才能更好地理解使用 Java 注解或代码作为配置元数据的方式。

Spring 为我们提供了多个 ApplicationContext 接口的实现。在独立的应用程序中,常见的实例化方式是创建 ClassPathXmlApplicationContextFileSystemXmlApplicationContext 的一个实例。

**不过,在我们日常的开发和工作中,我们基本上不需要显式地去实例化一个或多个 Spring 容器。**特别是在Web应用程序的场景下,通常只需在web.xml文件中简单地编写约8行标准的XML配置即可完成(你可以参考一些方便的方式来初始化Web应用程序的ApplicationContext)。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

所以,容器终于来啦!它就是 Spring 的 IoC 容器,负责管理 Bean 的实例化、配置和组装,而我们可以通过配置元数据来描述应用程序中的对象和它们之间的依赖关系。记住,我们一般不需要手动实例化 Spring 容器,特别是在 Web 应用程序中。

Spring IoC 容器怎样运行的?

从顶层上来看,Spring IoC 是这样运行的,就是将我们应用程序中的各种业务对象与配置元数据结合起来,使得我们在初始化 ApplicationContext 之后,有一个完整配置的、可用的应用程序。

image-20230525230621539

什么是配置元数据?

先说个结论,目前日常工作中,配置元数据基本都是以 Java 注解或者 Java 代码的方式来提供给 Spring 容器的,不过 XML 的方式我们也要学习,对于后续学习是有帮助的。

「配置元数据」是 Configuration Metadata,不是 Configure Metadata,这里的「配置」二字是名词,不是动词,千万不要理解成去配置元数据。

这个配置元数据,实际就是用来描述配置的数据,上面我也说了,我们可以用 Java 注解或者 Java 代码的方式来描述配置,也可以用 XML 的方式来描述数据。

所以现在,相信你已经明白何为配置元数据了,所以学习下以 XML 格式的文件作为配置元数据。

XML 格式的配置元数据

配置元数据以简单直观的 XML 格式提供,这也是本系列前大半部分内容用来传达 Spring IoC 容器关键概念和特性的方式,也正如前面说的,学习 XML 的配置方式,便于我们后续学习 Java 注解或者 Java 代码的配置方式。

下面的示例展示了基于XML的配置元数据的基本结构

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="..." class="...">  
        <!-- 该 bean 的协作者和配置写在此处 -->
    </bean>

    <bean id="..." class="...">
        <!-- 该 bean 的协作者和配置写在此处 -->
    </bean>

    <!-- 更多的 bean 定义写在此处 -->

</beans>

上面的示例中,主要使用了 <bean> 元素(或者说标签),该元素有两个属性,idclass

  • id 属性:它是一个字符串,用于标识单个 bean 定义。

  • class 属性:它定义了 bean 的类型,并使用完全限定类名(又称全限定名、全类名。多种叫法,都是同一个东西)。

我们习惯说把对象交给 Spring IoC 容器管理,那你如何个交法呢

上面的 XML 已经给出了答案,就是定义 Bean,我们每定义一个 Bean,就是将对应的类的对象交给了 Spring IoC 容器了

这些 Bean 的定义就是构成我们应用程序中的各种实际对象。一般我们在开发的时候,都会分层次的,控制层、业务层、持久层、表现层(视图层)或者其他层次,然后我们就会定义业务层对象、持久层对象、表现层对象等等。

在上一篇中,我举了个例子,员工和部门的,让这两个东西交给了 Spring IoC 管理了,实际上,在日常开发中,是不会这样做的,不会配置细粒度的领域对象(Domain Object)。因为一般这些领域对象都是在业务层和持久层中创建或者加载的。

如何实例化一个 Spring IoC 容器?

上面我也说过,在我们日常的开发和工作中,我们基本上不需要显式地去实例化一个或多个 Spring 容器的。

但是我们现在在学习,就有必要了解如何手动去实例化一个 Spring IoC 容器。

一行代码就能够实例化一个 Spring IoC 容器:

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

在 XML 为配置元数据的情况下,我们可以创建一个 ClassPathXmlApplicationContext 对象,它是 ApplicationContext 的一个实现类,提供给我们的构造函数的参数是一条或多条路径是资源字符串,它让容器从各种外部资源(如本地文件系统、Java CLASSPATH 等)加载配置元数据,这样我们就实例化一个 Spring IoC 容器,context 对象就是这个容器了。

image-20230602233931031

现在我们将持久层的对象和业务层的对象定义到 XML 中,先创建好需要的类和接口:

image-20230602235701751

接着,在 daos.xml 中定义如下两个 bean,交给 Spring IoC 管理:

<?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="roleDao" class="cn.god23bin.demo.dao.impl.RoleDaoImpl">
        <!-- 该 bean 的协作者和其他配置 -->
    </bean>

    <bean id="userDao" class="cn.god23bin.demo.dao.impl.UserDaoImpl">
        <!-- 该 bean 的协作者和其他配置 -->
    </bean>

    <!-- 其他的持久层的 bean 定义在这里 -->

</beans>

services.xml 同理:

<?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">

    <!-- 引入另一个 XML 定义的 bean -->
    <import resource="daos.xml"/>

    <bean id="userService" class="cn.god23bin.demo.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao" />
        <property name="roleDao" ref="roleDao" />
    </bean>

    <!-- 其他的业务层的 bean 定义在这里 -->

</beans>

services.xml 中,使用 <import /> 可以让 Bean 的定义跨越 XML 文件。一般每个单独的 XML 配置文件代表了我们应用中的一个逻辑层或者模块,就如同这里的 daos.xmlservices.xml

使用 Spring IoC 容器

我们把对象交给了 Spring IoC 容器管理,让它帮我们创建对象以及处理对象之间的依赖关系。

在上面的 XML 中,我们定义了 UserServcie 对象,即把 UserService 这个对象交给了 Spring IoC,那么如何从容器获取它呢?

ApplicationContext 是一个高级工厂的接口,能够维护不同 Bean 及其依赖关系的注册表。我们通过使用方法 T getBean(String name, Class requiredType),就可以获取到我们需要的 Bean 对象。

代码如下:

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
UserService userService = context.getBean("userService", UserService.class);
String roleList = userService.getRoleList();
String username1 = userService.getUsernameById(23L);
String username2 = userService.getUsernameById(24L);
System.out.println("roleList = " + roleList + " | username1 = " + username1 + " | username2 = " + username2);

输出:

image-20230603002316783

总结

以上,就是本文的所有内容,主要讲了什么是 Spring IoC 容器,介绍了 BeanFactoryApplicationContext

实际上这个 ApplicationContext 就代表容器,它会读取我们的配置元数据,这样它就知道该去管理哪些对象了。

也介绍了什么是 Bean,实际上就是被容器管理的对象,都是所谓的 Bean,也习惯称为 Bean 对象。

还介绍了 Spring IoC 容器从顶层上来看是怎样运行的,就是将各种业务对象和配置元数据相结合,组成一个完整配置的、可用的应用程序。

对于配置元数据,这个可以有多种形式,可以是 XML,可以是 Java 注解,可以是 Java 代码。

最后就介绍了如何去实例化并使用 Spring IoC 容器,虽然我们日常开始是不会这样去做的,不会去创建一个容器,然后通过容器的 getBean 去获取 Bean 进行操作,但是我们就是需要了解学习,因为这些就是 Spring 的基础。

最后的最后

希望各位屏幕前的靓仔靓女们给个三连!你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

咱们下期再见!

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

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

相关文章

day2 -- 数据库的安全管理和维护

brief 访问控制的目的不仅仅是防止用户的恶意企图。数据梦魇更为常见的是无意识错误的结果&#xff0c;如错打MySQL语句&#xff0c;在不合适的数据库中操作或其他一些用户错误。通过保证用户不能执行他们不应该执行的语句&#xff0c;访问控制有助于避免这些情况的发生。管理…

Makerbase SimpleFOC ESP32 例程6 双电机闭环位置力矩互控

Makerbase SimpleFOC ESP32 例程6 双电机闭环位置力矩互控 第一部分 硬件介绍 1.1 硬件清单 序号品名数量1ESP32 FOC V1.0 主板12YT2804电机2312V电源适配器14USB 线156pin杜邦线2 注意&#xff1a;YT2804是改装的云台无刷电机,带有AS5600编码器&#xff0c;可实现360连续运…

Go 字节跳动—从需求到上线全流程

走进后端开发流程 整个课程会带大家先从理论出发&#xff0c;思考为什么有流程 大家以后工作的团队可能不一样&#xff0c;那么不同的团队也会有不同的流程&#xff0c;这背后的逻辑是什么 然后会带大家按照走一遍从需求到上线的全流程&#xff0c;告诉大家在流程的每个阶段&am…

angular环境安装 (含nodejs详细安装步骤)

在安装本次环境之前&#xff0c;需要先把本机上的nodejs环境卸载&#xff0c;环境变量手动删除&#xff01;安装过程种环境才不会产生副作用&#xff01;实际项目安装的一次记录&#xff0c;踩了太多坑&#xff0c;记录一下&#xff0c;旨在记录&#xff01;项目需要两个不用版…

常用设计模式介绍~~~ Java实现 【概念+案例+代码】

前言 想要读懂源码、让自己的代码写的更加优雅&#xff0c;重构系统等。理解设计模式的思想&#xff0c;可以让我们事半功倍。以下稍微整理了常用的设计模式、每一种设计模式都有详细的概念介绍、案例说明、代码实例、运行截图等。这里给出目录导航。 目录 一、创建型模式 【一…

现在的面试把我卷崩溃了....

现在的面试也太卷了&#xff0c;前几天组了一个软件测试面试的群&#xff0c;没想到效果直接拉满&#xff0c;看来大家对面试这块的需求还是挺迫切的。昨天我就看到群友们发的一些面经&#xff0c;感觉非常有参考价值&#xff0c;于是我就问他还有没有。 结果他给我整理了一份…

Linux命令学习之cd

cd是进入某个目录的命令。man 1 cd看一下cd的使用说明。 发现cd是一个Shell内置命令。内置命令可以使用help 命令行来看一下帮助&#xff0c;比如help cd就可以看一下cd的帮助。 图中的[dir]就是参数&#xff0c;这个参数是目录名&#xff0c;比如可以使用cd /可以进入根目录…

外包派遣3年华为,合同结束转正,转正后工资12k-15k,13薪,包三餐,值得去吗?

“但凡有点机会&#xff0c;千万别去外包! ” 在程序员圈子里面&#xff0c;外包程序员似乎永远处于一个尴尬的角色&#xff0c;如果你说他们不是程序员吧&#xff0c;他们也是程序员。应该说是外包这个词比较尴尬吧。赶着和正式工一样的伙&#xff0c;待遇缺天差地别&#xf…

使用VS2019如何创建Win32的项目?

闲来无事&#xff0c;想学习一下Win32的开发&#xff0c;使用VS2019如何创建Win32的项目&#xff1f;费了老大的劲儿&#xff0c;终于捣鼓出来&#xff0c;现在记录一下。 1 创建新项目&#xff0c;在筛选栏选择C Windows 桌面&#xff0c;如下图&#xff0c;选择第一个“Windo…

由于找不到msvcr90.dll无法继续执行代码的5个修复方法

msvcr90.dll是Microsoft Visual C 2008 Redistributable软件包中的一个库文件&#xff0c;它是用于在Windows操作系统上运行C应用程序的重要文件之一。当我们电脑系统中的msvcr90.dll丢失或者损坏了&#xff0c;就会导致很多软件跟游戏无法打开运行&#xff0c;会提示“由于找不…

Linux文件权限及用户管理

文件权限 在Linux中&#xff0c;每个文件和目录都有一组权限&#xff0c;这些权限决定了哪些用户可以访问文件或目录&#xff0c;以及他们可以进行什么样的操作。权限分为三类&#xff1a; 所有者权限&#xff1a;这些权限适用于文件或目录的所有者。 组权限&#xff1a;这些…

vue+elementui+nodejs毕业设计选题管理系统x7xs6

为了实现对不同角色的分权限管理&#xff0c;从而让各个用户各司其职。学生用户需要登录系统后才能够进行毕设相关文件上传与查看&#xff0c;教师用户需要登录后才能够在线查看毕设相关文件并审核留言等。管理人员需要登录才能够管理各种功能&#xff0c;这三种用户的权限如下…

初阶二叉树的相关性质定理及题目练习

前言&#xff1a; 前面我们介绍了初阶二叉树的相关知识&#xff0c;二叉树常考的还是链式二叉树&#xff0c;而且二叉树也会考很多选择题&#xff0c;本文重点是在给出一些常考的二叉树的性质定理推导和经典练习题目配合强化巩固知识。 目录 一、二叉树的常见性质定理 二、常…

力扣高频SQL50题(基础版)——第四天

力扣高频SQL50题(基础版)——第四天 1 每台机器的进程平均运行时间 1.1 题目内容 1.1.1 基本题目信息1 1.1.2 基本题目信息2 1.1.3 示例输入输出 1.2 示例sql语句 SELECT machine_id,ROUND(SUM(IF(activity_typeend,timestamp,timestamp*-1))/count(distinct process_id),3…

English Learning - L3 作业打卡 Lesson4 Day26 2023.5.30 周二

English Learning - L3 作业打卡 Lesson4 Day26 2023.5.30 周二 引言&#x1f349;句1: It is easy to find my husband in a crowd.成分划分弱读连读语调 &#x1f349;句2: He stands almost two meters tall.成分划分爆破语调 &#x1f349;句3: He is a tall drink of wate…

嵌入式系统中u-boot和bootloader到底有什么区别

嵌入式软件工程师都听说过 u-boot 和 bootloader&#xff0c;但很多工程师依然不知道他们到底是啥。 今天就来简单讲讲 u-boot 和 bootloader 的内容以及区别。 Bootloader Bootloader从字面上来看就是启动加载的意思。用过电脑的都知道&#xff0c;windows开机时会首先加载…

【Nginx性能优化系列】Nginx绑定特定的CPU性能测评

【Nginx性能优化系列】Nginx绑定特定的CPU性能测评 前导知识说明:   CPU内部的缓存叫Cache   比如一颗CPU有4核,每个核心都有自己的独立缓存,以及所有核心的共享缓存。缓存分为一级缓存、二级缓存、三级缓存,一级缓存的速率基本上CPU相当,当然一级缓存的存储空间也较小…

【抽象类和接口】

目录 1.抽象类1.1什么是抽象类1.2抽象类语法1.3抽象类与普通类的区别 2.抽象类的特性2.1 特性2.2抽象类的作用 3.接口3.1什么是接口3.2语法规范3.3接口的使用3.4接口的特性3.5 实现多个接口3.6 接口的继承 4.接口的实例5.Clonable 接口和深拷贝5.1 浅拷贝5.2深拷贝 6. 抽象类和…

English Learning - L3 作业打卡 Lesson4 Day27 2023.5.31 周三

English Learning - L3 作业打卡 Lesson4 Day27 2023.5.31 周三 引言&#x1f349;句1: It is so crowded that we are packed like sardines – just like small fish in a can.成分划分弱读连读爆破语调 &#x1f349;句2: My supervisor at work is sometimes out to lunch.…

设计模式之database/sql 与Gorm设计原理

1.0 理解 database/sql 1.1 基本用法 - Quick Start 上面有几行错误 DSN相关知识&#xff1a; https://github.com/go-sql-driver/mysql#dsn-data-source-name https://en.wikipedia.org/wiki/Data_source_name 完整&#xff1a; 1.2 设计原理 极简接口设计原则&#xff1a; 对…