【Spring笔记02】Spring中的IOC容器和DI依赖注入介绍

这篇文章,主要介绍一下Spring中的IOC容器和DI依赖注入两个概念。

目录

一、IOC控制反转

1.1、什么是IOC

1.2、两种IOC容器

(1)基于BeanFactory的IOC容器

(2)基于ApplicationContext的IOC容器

二、DI依赖注入

2.1、什么是DI

2.2、四种依赖注入方式

(1)setter方法注入

(2)构造方法注入

(3)工厂方法注入

(4)静态方法注入


一、IOC控制反转

1.1、什么是IOC

IOC,英文全称是:Inversion Of Control,中文含义叫做:控制反转。

那具体什么是控制反转呢???

所谓的控制反转,是指:以前我们创建对象的方式是程序开发人员显式的通过【new】关键字进行创建,而到了Spring框架里面,我们对象的创建全部交给了Spring去创建,程序开发人员不需要知道对象是如何创建的,开发人员只需要从Spring里面获取需要的对象实例就可以使用了,这个过程我们就叫做控制反转。

控制反转,是一种主从换位的思想,就是说以前是开发人员创建对象,现在是Spring框架替我们创建对象,这就是将主从关系颠倒过来了。

控制反转的好处是什么呢???

我们可以看到,使用控制反转,可以不用显式的通过【new】创建对象,这样就可以减少很多的代码编写,提高一下开发效率了呗。

1.2、两种IOC容器

IOC容器主要作用就是:统一管理Bean的生命周期,以及Bean和Bean之间的依赖关系。

Spring框架里面,给我们提供了两种IOC容器,分别是:【BeanFactory】和【ApplicationContext】两大类。

(1)基于BeanFactory的IOC容器

BeanFactory位于spring-beans的jar包里面,是一个接口,它是Spring提供的最简单的IOC容器,基于BeanFactory接口实现的IOC容器只具备IOC和DI的功能,也就是说,BeanFactory的IOC容器只能够管理Bean的生命周期,以及Bean之间的依赖关系。

BeanFactory接口常见的实现类是:【XmlBeanFactory】类,这是一个通过读取XML配置文件的IOC容器。

BeanFactory特点:

功能简单,只具备IOC和DI的实现。

Bean实例化采用懒加载的方式(懒加载:只能主动调用getBean()方法获取Bean实例的时候才会去new创建对象)。

BeanFactory接口常用方法:

getBean():获取一个Bean对象。

BeanFactory常见实现类:

XmlBeanFactory类,这个类目前已经废弃,不推荐使用了。

BeanFactory代码案例:

public class ApplicationTest {public static void main(String[] args) throws FileNotFoundException {beanFactory();}private static void beanFactory() throws FileNotFoundException {// 1、获取 BeanFactory 容器ClassPathResource resource = new ClassPathResource("spring.xml");BeanFactory beanFactory = new XmlBeanFactory(resource);// 2、获取 bean 对象User user = beanFactory.getBean("user", User.class);}
}

(2)基于ApplicationContext的IOC容器

ApplicationContext是BeanFactory的一个子接口,基于ApplicationContext实现的IOC容器不仅具备BeanFactory的所有功能,并且还提供了额外的一些功能,例如:事件监听、国际化等等企业级功能。

ApplicationContext特点:

容器启动时候,就会实例化所有配置的Bean对象。

提供更多的功能,例如:事件传播,国际化等等功能。

ApplicationContext常见实现类:

ClassPathXmlApplicatinContext实现类:加载类路径下的配置文件(即:加载【src/main/resources】目录下路径)。

FileSystemXmlApplicationContext实现类:加载系统路径下中的配置文件(这个必须写完整的XML文件路径)。

ApplicationContext案例代码:

public class ApplicationTest {public static void main(String[] args) {applicationContext();}private static void applicationContext() {// 1、获取 ApplicationContext 容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");// 2、获取 Bean 对象User user = context.getBean("user", User.class);}
}

IOC是一种程序设计思想,并不是一种技术,而要实现IOC则需要通过DI依赖注入的方式,下面介绍一下什么是DI依赖注入???

二、DI依赖注入

2.1、什么是DI

DI,英文全称是:Dependency Injection,中文含义叫做:依赖注入。

依赖注入:这里的依赖是指Bean之间的依赖关系(引用关系,例如:A类使用B类对象,C类使用A类对象),注入是指给某个类中的属性赋值,依赖注入可以理解为当某个A类中引用了B类的实例对象,Spring会动态的将B类对象赋值到A类的属性里面,Spring框架这个动态赋值的操作我们就称为依赖注入。

在Spring框架里面,如果我们需要使用某个Bean对象的时候,我们不用自己创建就可以直接使用这个Bean对象,这是因为Spring框架已经给我们注入了所有的Bean。

什么是意思呢,举个栗子看看:

如果我们在某个A类里面使用到了B类的一个实例,此时Spring会自动将B类的实例注入到当前A类里面,而不需要我们再次通过new创建B的对象实例。

简单理解,依赖注入就是Spring框架自动帮我们把某个类中的属性已经赋值了,所以我们在使用的时候,就可以不用再次赋值,也就不会出现空指针的情况啦。

依赖注入的好处:通过依赖注入,可以极大程度上面降低类之间的耦合度,实现类与类之间的松耦合。

2.2、四种依赖注入方式

Spring框架中提供了四种依赖注入的方式,分别是如下所示:

  • 通过setter方法实现依赖注入
  • 通过工厂方法实现依赖注入
  • 通过静态工厂方法实现依赖注入
  • 通过构造方法实现依赖注入

(1)setter方法注入

Spring框架可以通过调用属性的【setter】方法进行属性赋值,从而实现依赖注入。Spring通过反射机制调用属性的【setXXX()】方法,将所需要的对象赋值给对应的类属性(注意:和具体的属性名称没有关系,只不过我们习惯将属性名称和setter方法名称命名相同)。

创建【Setter】测试类

public class Setter {private String uid;private String name;private String pass;public String getUid() {return uid;}public void setUid(String uid) {this.uid = uid;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return pass;}// 注意:这里的 setPassword 方法名称和 Pass属性不同public void setPassword(String pass) {this.pass = pass;}
}

配置spring.xml文件

setter方法注入,对应XML配置中的【<property>】标签。我们通过【<property>】标签就是采用的setter方法进行属性注入。

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 配置 Setter类 --><bean id="setter" class="com.spring.demo.pojo.Setter"><!-- 属性赋值 --><property name="uid" value="1001"/><property name="name" value="朱友斌"/><!-- 属性名称要和 setXxx() 对应的名称相同 --><property name="password" value="123456"/></bean></beans>

测试setter方法注入

public class SetterTest {public static void main(String[] args) {// 1、获取 ApplicationContext 容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");// 2、获取 Bean 对象Setter setter = context.getBean("setter", Setter.class);System.out.println(setter.getUid());System.out.println(setter.getName());System.out.println(setter.getPassword());}
}

以上,就是通过setter方法进行属性注入的一个案例,下一篇文章会详细的介绍各种依赖注入的方式以及各种数据类型的依赖注入,这里先大致有个了解。

(2)构造方法注入

Spring也支持通过构造方法进行属性注入(属性赋值),主要是调用Bean相应的构造方法。

Spring里面通过在XML配置文件中使用【<constructor-arg>】标签,就可以实现构造方法注入属性。

创建【Constructor】测试类

public class Constructor {public String uid;public String name;public String pass;// 构造方法注入属性public Constructor(String uid, String name, String pass) {this.uid = uid;this.name = name;this.pass = pass;}
}

添加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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 配置 Constructor 类 --><bean id="constructor" class="com.spring.demo.pojo.Constructor"><!-- 构造方法属性赋值 --><constructor-arg name="uid" value="1001"/><constructor-arg name="name" value="朱友斌"/><constructor-arg name="pass" value="123456"/></bean></beans>

测试构造方法注入

public class ConstructorTest {public static void main(String[] args) {// 1、获取 ApplicationContext 容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");// 2、获取 Bean 对象Constructor constructor = context.getBean("constructor", Constructor.class);System.out.println(constructor.uid);System.out.println(constructor.name);System.out.println(constructor.pass);}
}


构造方法注入,有两种方式,分别是:

  • 第一种方式:指定具体的参数名称进行赋值。
  • 第二种方式:根据构造方法中的参数位置进行赋值。

上面我们就是通过【<constructor-arg>】标签的参数名称进行赋值,这里我再给出通过参数位置(参数位置从0开始编号)进行赋值的代码配置,如下所示:

<bean id="constructor" class="com.spring.demo.pojo.Constructor"><!-- 构造方法属性赋值 --><constructor-arg index="0" value="1001"/><constructor-arg index="1" value="朱友斌"/><constructor-arg index="2" value="123456"/>
</bean>

(3)工厂方法注入

Spring框架实例化Bean是调用无参构造方法实现的,所以如果某个Bean没有无参构造方法,并且没有通过有参构造方法进行注入,那么在Spring实例化的时候就会失败,并且抛出异常。如何解决这个Bean无法实例化的问题呢???

Spring框架提供了实例工厂方法,我们可以通过工厂方法进行实例化操作。

如何使用实例工厂方法进行依赖注入???

  • 使用实例工厂方法,需要创建一个实例工厂,然后在工厂类中提供一个创建实例的方法。
  • 然后在目标Bean里面,配置【factory-bean】和【factory-method】两个属性。
  • 【factory-bean】作用:告诉Spring,当前这个Bean是从哪个实例工厂bean获取。
  • 【factory-method】作用:告诉Spring,当前这个Bean是从工厂类中哪个method方法进行获取。

创建【Person】实体类

public class Person {public Integer pid;public String name;// 无参构造方法public Person(Integer pid, String name) {this.pid = pid;this.name = name;}
}

创建【FactoryMethod】工厂类

public class FactoryMethod {// 工厂方法public Person getInstance() {return new Person(1002, "朱友斌");}
}

添加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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 配置工厂类 --><bean id="factory" class="com.spring.demo.pojo.FactoryMethod"/><!-- 配置 Person 类 --><bean id="person" class="com.spring.demo.pojo.Person" factory-bean="factory" factory-method="getInstance"/></beans>

在XML配置文件里面,需要配置【factory-bean】和【factory-method】两个属性,这是告诉Spring,当前这个Person类实例化,是去找一个叫做【factory】的bean里面的【getInstance()】方法进行获取。


编写测试类,查看Person是否实例化成功

public class FactoryMethodTest {public static void main(String[] args) {// 1、获取 ApplicationContext 容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring02.xml");// 2、获取 Bean 对象Person person = context.getBean("person", Person.class);System.out.println(person.pid);System.out.println(person.name);}
}

以上,就是通过实例工厂方法进行Bean的依赖注入。

(4)静态方法注入

从(3)里面,我们学习了通过实例工厂方法进行Bean的依赖注入,基本分为两个步骤,第一步是创建工程类的Bean,第二步是根据工程类的Bean创建目标Bean的实例。

这里我们可以发现,我们创建目标Bean的时候依赖于工厂类的Bean对象,所以这里有个问题,如果我们的工厂类的Bean也没有办法实例化,那实例工厂方法注入不就没有办法实现了吗???

为了解决实例工厂方法的缺陷,Spring也提供了静态工厂方法进行Bean的注入。既然实例工厂没办法实例化,那我们就采用静态工厂,因为静态工厂是可以直接通过类进行访问的,和实例对象没有关系,所以我们就可以通过一个静态方法,这个静态方法就是用于创建目标Bean的实例对象。

静态工厂方法依赖注入

  • 创建静态工厂类,提供一个静态工厂方法,用于获取目标Bean的对象。
  • 然后在配置文件里面通过【factory-method】属性配置获取bean对象的静态方法。

创建【StaticFactoryMethod】静态工厂类

public class StaticFactoryMethod {// 静态工厂方法public static Person getInstance() {return new Person(1002, "朱友斌");}
}

添加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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 通过静态工厂方法获取 Person 类实例 --><bean id="person" class="com.spring.demo.pojo.StaticFactoryMethod"  factory-method="getInstance"/></beans>

创建测试类,测试是否依赖注入成功

public class StaticFactoryMethodTest {public static void main(String[] args) {// 1、获取 ApplicationContext 容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring03.xml");// 2、获取 Bean 对象Person person = context.getBean("person", Person.class);System.out.println(person.pid);System.out.println(person.name);}
}

以上,就是通过静态工厂方法进行依赖注入。

综上,讲述了Spring框架中的IOC容器,DI依赖注入以及四种依赖注入的方式。依赖注入的四种方式主要记住setter方法和构造方法注入,因为实例工厂方法、静态工厂方法在实际开发中不常用

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

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

相关文章

stm32-SPI协议

SPI协议详解&#xff08;图文并茂超详细&#xff09; SPI通讯协议 于是我们想有没有更好一点的串行通讯方式&#xff1b;相比较于UART&#xff0c;SPI的工作方式略有不同。 SPI是一个同步的数据总线&#xff0c;也就是说它是用单独的数据线和一个单独的时钟信号来保证发送端和…

MySQL中的 增 删 查 改(CRUD)

目录 新增 insert into 表名 value(数据&#xff0c;数据),.......&#xff1b; insert into 表名&#xff08;列1&#xff0c;列2.....&#xff09; value(数据&#xff0c;数据),.......&#xff1b; datatime 类型的数据如何插入&#xff1f; 查询 select * from 表名…

动态调整系统主题色(4): CssVar 与 Variant 方案的探索

动态调整系统主题色(4): CssVar 与 Variant 方案的探索 动态调整系统主题色(4): CssVar 与 Variant 方案的探索 前言方案的介绍与比较 CssVar (CSS 变量方案)CSS 变量方案与 tailwindcss 的结合Variant 方案 2种方案在小程序上的示例之前的几篇 前言 这篇已经是动态调整系统…

Docker 的数据管理与Docker 镜像的创建

------------------Docker 的数据管理--------------------- 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&#xff09;。 1&#xff0e;数据卷 数据卷是一个供容器使用的特殊…

什么是Vue的JSX语法?如何使用JSX语法

Vue的JSX语法&#xff1a;更接近JavaScript的模板语言 Vue.js是一个流行的JavaScript框架&#xff0c;用于构建交互式的Web应用程序。虽然Vue通常使用模板语法来构建用户界面&#xff0c;但它也提供了JSX语法的支持&#xff0c;使开发人员能够更接近JavaScript的表达方式来构建…

分享几个优秀开源免费管理后台模版,建议收藏!

大家好&#xff0c;我是 jonssonyan 今天和大家分享一些免费开源的后台管理页面&#xff0c;帮助大家快速搭建前端页面。为什么要用模板&#xff1f;道理很简单&#xff0c;原因是方便我们快速开发。我们不应该花太多的时间在页面调整上&#xff0c;而应该把精力放在核心逻辑和…

re学习(37)DASCTF 2023 0X401七月暑期挑战赛 controflow

程序通过改变栈里面的返回地址来控制程序的控制流 从而达到混淆的效果 左侧有许多被hook的函数 在每个函数开头设置断点 然后观察程序的运行流程 会发现输入的数据会进行 异或 相加 异或 相减 相乘 异或等操作 要注意部分运算的索引是 从[10]开始的 具体思路参考&#xf…

黑豹程序员-架构师学习路线图-百科:JSON替代XML

文章目录 1、数据交换之王2、XML的起源3、JSON诞生4、什么是JSON 1、数据交换之王 最早多个软件之间使用txt进行信息交互&#xff0c;缺点&#xff1a;纯文本&#xff0c;无法了解其结构&#xff1b;之后使用信令&#xff0c;如&#xff1a;电话的信令&#xff08;拨号、接听、…

三十、【进阶】B-Trees的演变过程

1、索引结构 &#xff08;1&#xff09;二叉树 &#xff08;2&#xff09;B-Tree树 B-Tree树最大度数为5&#xff0c;代表每一个节点最多存储4个key(每个节点最多存储4个数据)&#xff0c;5个指针(可以指向5个子节点)。 2、演变过程&#xff08;最大度数为5&#xff09; &…

数据挖掘(3)特征化

从数据分析角度&#xff0c;DM分为两类&#xff0c;描述式数据挖掘&#xff0c;预测式数据挖掘。描述式数据挖掘是以简介概要的方式描述数据&#xff0c;并提供数据的一般性质。预测式数据挖掘分析数据建立模型并试图预测新数据集的行为。 DM的分类&#xff1a; 描述式DM&#…

记录本地部署Stable-diffusion所依赖的repositories和一些插件

今天按照其他文章的步骤拉取好了https://github.com/AUTOMATIC1111/stable-diffusion-webui后&#xff0c;点击webui-user.bat后发现&#xff0c;repositories和models还得慢慢拉取&#xff0c;好吧&#xff0c;GitHub Desktop&#xff0c;启动&#xff01; BLIP: https://git…

使用sqlmap获取数据步骤

文章目录 1.使用sqlmap获取所有数据库2.使用sqlmap获取当前连接数据库3.使用sqlmap获取当前数据库下所有表名4.使用sqlmap获取当前数据库下某个表下所有列名5.使用sqlmap获取当前数据库下某个表下指定字段的数据6.测试当前用户是否是管理员7.使用burpsqlmap批量检测8.脱库命令9…

c++使用ifstream和ofstream报错:不允许使用不完整的类型

学习《C Primer》关于IO库的部分&#xff0c;输入284页的的代码&#xff0c;出现了报错&#xff1a; 不允许使用不完整的类型 原来的代码&#xff1a; #include <iostream> #include <vector> using namespace std;int main(int argc, char **argv) {ifstream in…

Next.js 入门笔记

前言 之前初步体验了 React 的魅力, 又看文档理解了一下 useState 和 useEffect, 目前初步理解的概念是: useState 用来声明在组件中使用并且需要修改的变量 useEffect 用来对 useState 声明的变量进行初始化赋值 可能理解的不太准确, 不过大概差不多是这么个意思. 但是再往后…

【AI视野·今日NLP 自然语言处理论文速览 第四十七期】Wed, 4 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 4 Oct 2023 Totally 73 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Contrastive Post-training Large Language Models on Data Curriculum Authors Canwen Xu, Corby Rosset, Luc…

数字孪生、AR和VR如何改进数据中心设计

数据中心基础设施管理(DCIM)已存在多年&#xff0c;它在许多数据中心被广泛使用&#xff0c;但还没有普遍使用&#xff0c;由于两个因素&#xff0c;这种情况正在改变&#xff1a;数字化的概念正在普及&#xff0c;IT与运营技术(OT)系统(如建筑管理系统(BMS)和电源管理工具)的集…

从零开始的C++(五)

1.类和对象的补充 当对象是const修饰的常量时&#xff0c;形参中的this是隐含的&#xff0c;那么该如何写函数才能传常量对象呢&#xff1f;如果还是按照正常的方式写&#xff0c;则会出现实参是const修饰的&#xff0c;形参没有&#xff0c;出现了权限的扩大&#xff0c;无法…

Django 模型层的操作(Django-05 )

一 模型层的解读 Django中内嵌了ORM框架&#xff0c;不需要直接编写SQL语句进行数据库操作&#xff0c;而是通过定义模型类&#xff0c;操作模型类来完成对数据库中表的增删改查和创建等操作。 O 是object&#xff0c;也就类对象的意思。R 是relation&#xff0c;翻译成中文是…

快手直播显示请求过快

快手直播显示请求过快 问题描述情况一问题描述原因分析解决方案:情况二问题描述解决方法问题描述 在使用快手直播网页版时,如果我们的请求过于频繁,系统可能无法及时显示所需内容。这种情况下,我们会收到一个稍后重试的提示。一般有两种情况。一种是直接返回一段json,里面…

图像和视频上传平台Share Me

本文完成于 6 月&#xff0c;所以反代中&#xff0c;域名演示还是使用的 laosu.ml&#xff0c;不过版本并没有什么变化&#xff1b; 什么是 Share Me &#xff1f; Share Me 是使用 Next.js 和 PocketBase 的自托管图像和视频上传平台&#xff0c;具有丰富的嵌入支持和 API&…