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

news2024/12/24 2:17:27

这篇文章,主要介绍一下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/beans
       http://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/beans
       http://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/beans
       http://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/beans
       http://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.coloradmin.cn/o/1063142.html

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

相关文章

Vue MVVM 模型

一、什么事MVVM 模型 MVVM 是 Model-View-ViewModel 的缩写&#xff0c;它是一种软件架构风格 Model&#xff1a;模型&#xff0c; 数据对象&#xff08;data 函数&#xff09;&#xff0c;如下图 View&#xff1a;视图&#xff0c;模板页面&#xff08;用于渲染数据&#xf…

掌握Mac菜单栏,尽在Bartender 5!菜单栏图标管理软件的终极推荐!

作为Mac用户&#xff0c;菜单栏是我们每天使用电脑时最常接触的区域之一。然而&#xff0c;随着我们安装越来越多的应用程序&#xff0c;菜单栏上的图标往往变得拥挤不堪&#xff0c;给我们的工作和生活带来了不便。 幸运的是&#xff0c;有了Bartender 5这款强大的菜单栏图标…

数据结构与算法(Python)

数据结构与算法 算法基础时间复杂度空间复杂度 递归实例&#xff1a;汉诺塔问题 查找顺序查找&#xff08;线性查找&#xff09;二分查找&#xff08;折半查找&#xff09;比较 排序冒泡排序选择排序插入排序快速排序快排和冒泡的时间比较 堆排序树堆堆的向下调整 堆排序过程时…

除静电设备的工作原理及应用

除静电设备主要包括静电消除器、静电接地装置、静电消除风机等&#xff0c;它们的工作原理和应用如下&#xff1a; 静电消除器&#xff1a;静电消除器的工作原理是利用电离和电击的原理来中和电荷。它包括一个金属板和一个高压电源。当静电消除器接通电源后&#xff0c;金属板…

Redis最常见应用场景

缓存&#xff08;Cache&#xff09; Redis的第一个应用场景是Redis作为缓存对象来加速Web应用的访问。 在该场景下&#xff0c;有一些存储于数据库中的数据会被频繁访问&#xff0c;如果频繁的访问数据库&#xff0c;数据库负载会升高&#xff0c;同时由于数据库IO比较慢&…

阿里云服务器更换公网IP地址的方法流程

阿里云服务器可以更换IP地址吗&#xff1f;可以的&#xff0c;创建6小时以内的云服务器ECS可以免费更换三次公网IP地址&#xff0c;超过6小时的云服务器&#xff0c;可以将公网固定IP地址转成弹性EIP&#xff0c;然后通过换绑EIP的方式来更换IP地址。阿里云服务器网分享阿里云服…

阿里云服务器地域节点怎么选择合适?啥是可用区?

阿里云服务器地域和可用区怎么选择&#xff1f;地域是指云服务器所在物理数据中心的位置&#xff0c;地域选择就近选择&#xff0c;访客距离地域所在城市越近网络延迟越低&#xff0c;速度就越快&#xff1b;可用区是指同一个地域下&#xff0c;网络和电力相互独立的区域&#…

基于遗传算法的新能源电动汽车充电桩与路径选择(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

JavaScript系列从入门到精通系列第十六篇:JavaScript使用函数作为属性以及枚举对象中的属性

文章目录 前言 1&#xff1a;对象属性可以是函数 2&#xff1a;对象属性函数被称为方法 一&#xff1a;枚举对象中的属性 1&#xff1a;for...in 枚举对象中的属性 前言 1&#xff1a;对象属性可以是函数 对象的属性值可以是任何的数据类型&#xff0c;也可以是函数。 v…

RHEL - 订阅、注册系统和 Yum Repository

《OpenShift / RHEL / DevSecOps 汇总目录》 演示环境说明 本文需要有 redhat.com 账号以及包含 RHEL 的有效订阅。 演示环境使用了通过 minimal 方式安装的 RHEL 7.6 环境&#xff0c;RHEL 可以访问互联网。 注册和注销 RHEL 系统 在 RHEL 中执行以下命令查看当前 RHEL 版…

第P8周—YOLOv5-C3模块实现

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/Nb93582M_5usednAKp_Jtw) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https://mtyjkh.blog.csdn.net/)** >- **&#x1f680;…

transformer不同的包加载模型的结构不一样

AutoModel AutoModelForTokenClassification 结论&#xff1a; AutoModel加载的模型与AutoModelForTokenClassification最后一层是不一样的&#xff0c;从这个模型来看&#xff0c;AutoModelForTokenClassification加载的结果是对的 问题&#xff1a; 为什么AutoModel和Aut…

网络探索之浏览器解析URL

目录 解析URL 特殊情况&#xff1a; 请求响应格式说明 多次请求 解析URL 浏览器是一个具备很多功能的计算机&#xff0c;不仅仅是访问网络浏览信息&#xff0c;使用具体哪个功能是通过url的开头进行区分的&#xff0c;这部分也叫做协议。 协议类型举例&#xff1a; 1.使用…

Windowsold文件夹作用以及删除方法

引言 2021年6月24日&#xff0c;微软正式发布全新操作系统Windows 11。Windows 11系统于2021年10月5日开始全面推送。2021年10月以后生产的电脑已经预装Windows 11系统。刚开始会有一部分人不适应win 11系统&#xff0c;会选择退回win10。现在win11已经推出了稳定版&#xff0…

Gmail 将停止支持基本 HTML 视图

根据 Google 支持文档的更新内容&#xff0c;Gmail 将从明年 1 月起停止支持基本 HTML 视图。 ▲ Gmai 基本 HTML 视图界面 目前网页版 Gmail 提供两个界面&#xff1a;基本 HTML 视图和标准视图。停止支持基本 HTML 视图后&#xff0c;当前打开经典模式的基本 HTML 视图模式 …

【Pandas】数据分组groupby

本文目标&#xff1a; 应用groupby 进行分组对分组数据进行聚合,转换和过滤应用自定义函数处理分组之后的数据 文章目录 1. 数据聚合1.1 单变量分组聚合1.2 Pandas内置聚合方法1.3 聚合方法使用Numpy的聚合方法自定义方法同时计算多种特征向agg/aggregate传入字典 2. 数据转换…

好文学作品的鉴赏标准

好文学作品的鉴赏标准 2023年诺贝尔文学奖颁给了挪威剧作家约恩福瑟。由于之前的博彩公司给中国作家残雪开出了最高的赔率&#xff0c;以及诺贝尔官方推特在揭晓奖项前发布了一张泰戈尔99年前访华的老照片&#xff0c;残雪的获奖氛围在国内各类媒体的渲染下被拉至极高。当奖项…

除静电离子风枪的工作原理及应用

除静电离子风枪的工作原理是利用高压电离空气产生离子风&#xff0c;将静电荷从物体表面中和或分离出来&#xff0c;达到消除静电的目的。它包括一个高压电离器和一个风扇&#xff0c;高压电离器将空气电离成正负两种离子&#xff0c;风扇将离子风喷出。 具体来说&#xff0c;除…

【图像处理GIU】图像分割(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【最终版】tkinter+matplotlib实现一个强大的绘图系统

文章目录 辅助坐标轴功能实现代码优化源代码 Python绘图系统&#xff1a; 前置源码&#xff1a; Python打造动态绘图系统&#x1f4c8;一 三维绘图系统 &#x1f4c8;二 多图绘制系统&#x1f4c8;三 坐 标 轴 定 制&#x1f4c8;四 定制绘图风格 &#x1f4c8;五 数据生成导入…