前言

欢迎来到本篇文章!通过上一篇什么是 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 之后,有一个完整配置的、可用的应用程序。

什么是配置元数据?

先说个结论,目前日常工作中,配置元数据基本都是以 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 对象就是这个容器了。

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

接着,在 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);

输出:

总结

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

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

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

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

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

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

最后的最后

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

咱们下期再见!

Spring 核心概念之一 IoC的更多相关文章

  1. SSM 五:Spring核心概念

    第五章:Spring核心概念 一.Spring Ioc 优点: 1.低侵入式设计 2.独立于各种应用服务器 3.依赖注入特性将组建关系透明化,降低耦合度 4.面向切面编程的特性允许将通用性任务集中式处 ...

  2. Spring 核心概念

    Spring 核心概念 引言 本文主要介绍 Spring 源码中使用到的一些核心类 1. BeanDefinition BeanDefinition表示Bean定义,BeanDefinition 中存 ...

  3. Spring的俩大核心概念:IOC、AOP

    1.Spring 有两个核心部分: IOC 和 Aop (1)IOC:控制反转,把创建对象过程交给 Spring 进行管理   (2)Aop:面向切面,不修改源代码进行功能增强 2.Spring 特点 ...

  4. Spring核心——设计模式与IoC

    “Spring”——每一个Javaer开发者都绕不开的字眼,从21世纪第一个十年国内异常活跃的SSH框架,到现在以Spring Boot作为入口粘合了各种应用.Spring现在已经完成了从web入口到 ...

  5. Spring系列(一):Spring核心概念

    一.Spring概念 Spring是一种多层的J2EE应用程序框架,其核心就是管理资源组件以及依赖关系,Spring框架为现代基于java的企业应用程序提供了一个全面的编程和配置模型. 二.Sprin ...

  6. Spring核心概念和案例

    一.Spring概念 1.Spring框架概述 轻量级的Java EE开源框架,它是由Rod Johnson为了解决企业应用程序开发的复杂性而创建, Spring框架提供了一个开发平台,用于整合其他技 ...

  7. Spring核心原理之IoC容器初体验(2)

    本文节选自<Spring 5核心原理> 1 IoC与DI基本概念 IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建.依赖,反转给容器来帮忙实现 ...

  8. 第一章 spring核心概念

    一.Spring作用:管理项目中各种业务Bean(service类.Dao类.Action类),实例化类,属性赋值 二.Spring IOC(Inversion of Control )控制反转,也被 ...

  9. 30个类手写Spring核心原理之Ioc顶层架构设计(2)

    本文节选自<Spring 5核心原理> 1 Annotation(自定义配置)模块 Annotation的代码实现我们还是沿用Mini版本的,保持不变,复制过来便可. 1.1 @GPSer ...

  10. spring核心思想:IOC(控制反转)和DI(依赖注入)

    Spring有三大核心思想,分别是控制反转(IOC,Inversion Of Controller),依赖注入(DI,Dependency Injection)和面向切面编程(AOP,Aspect O ...

随机推荐

  1. 如何通过Java代码在Word中创建可填充表单

    有时候,我们需要制作一个Word模板文档,然后发给用户填写,但我们希望用户只能在指定位置填写内容,其他内容不允许编辑和修改.这时候我们就可以通过表单控件来轻松实现这一功能.本文将为您介绍如何通过Jav ...

  2. GaussDB(DWS)运维:导致SQL执行不下推的改写方案

    摘要:本文就针对因USING子句的书写方式可能导致MERGE INTO语句的执行不下推的场景,对USING子句的SQL语句进行改写一遍,整个SQL语句可以下推. 本文分享自华为云社区<Gauss ...

  3. uniApp安卓离线SDK运行

    一.下载uniapp提供的离线SDK包 下载地址:https://nativesupport.dcloud.net.cn/AppDocs/download/android 版本:2022年09月26日 ...

  4. 重打包APK绕过签名校验

    这里先提一种针对性校强但简单好理解的办法,纯Java实现,代码大概也就50行不到吧. 还有更强的并且能过各种保护(反调试反HOOK反内存修改等等)的万能方法,不过较复杂,长篇大论的,等有空整理出来再提 ...

  5. 一些随笔No.3

    1.开发应以业务为导向,技术只是手段 2.视觉上和程序上不一定是完全符合 比如,我所说的阻塞是视觉层面,或者是对用户而言的阻塞,而不是程序意义上的.我也许会传完参的同时销毁原组件,生成一个看起来一模一 ...

  6. Redis系列12:Redis 的事务机制

    Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...

  7. 统计模拟实验—R实现(蒲丰投针)

    统计模拟实验 统计模拟是数理统计.和计算机科学的结合,是一门综合性学科.在科学研究和生产实际的各个领域中,普遍存在着大量数据的分析处理工作.如何应用数理统计中的方法来解决实际问题,以及如何解决在应用中 ...

  8. [Linux]常用命令之【mount/umount】

    1 mount mount命令的作用是加载文件系统,它的用权限是超级用户或/etc/fstab中允许的使用者. 在Linux和Unix系统上,所有文件都是作为一个大型树(以/为根)的一部分访问的. 要 ...

  9. OpenAI-GPT

    操作系统:CentOS 7.6 安装依赖软件 进入 root 账号: sudo -i 安装部署 ChatGPT 必备的软件,并且启动 nginx : yum install git nginx -y ...

  10. Python argparse参数管理学习笔记1

    1.前言 最近尝试学习使用argparse进行参数管理,顺便改善一下我那丝毫都不专业的.简单粗暴的代码习惯. argparse模块可以让人轻松地编写用户友好地命令行接口,并且还能够自动生成帮助与使用手 ...