【Spring基础】关于Spring IoC的那些事

在这里插入图片描述

文章目录

  • 一、如何理解IoC
    • 1.1 Spring IOC 概述
    • 1.2 IoC 是什么
  • 二、Ioc 配置的方式
    • 2.1 xml 配置
    • 2.2 Java 配置
    • 2.3 注解配置
  • 三、依赖注入的方式
    • 3.1 setter方式
    • 3.2 构造函数
    • 3.3 注解注入
  • 小结

一、如何理解IoC

1.1 Spring IOC 概述

  控制反转 IoC(Inversion of Control)是一种设计思想,DI (依赖注入)是实现 IoC 的一种方法,也有人认为 DI 只是 IoC 的另一种说法。没有 IoC 的程序中我们使用面向对象编程对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试,如下图所示:
在这里插入图片描述

  要理解IoC,需要弄清楚 「到底什么被反转了?如何反转的」?IoC 是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移就是所谓反转。对于 Spring 而言,就是由 Spring 来控制对象的生命周期和对象之间的依赖关系。所有的类都会在 spring 容器中登记,告诉 spring 这是个什么东西,你需要什么东西,然后 spring 会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 spring。
  IoC 还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

1.2 IoC 是什么

  IoC 不是什么技术,而是一种设计思想,一个重要的面向对象编程的法则。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。我们来深入分析一下:

  • 谁控制谁,控制什么:传统 Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象。而 IoC 是有专门一个容器来创建这些对象,即由 Ioc 容器来控制对象的创建。关于谁控制谁?当然是 IoC 容器控制了对象;至于控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
  • 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象。那为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转。至于哪些方面反转了?依赖对象的获取被反转了。

  在传统程序设计下,都是主动去创建相关对象然后再组合起来,我们需要用到那个类的对象,只需要 new 它就可以产生该类的对象了,然在在通过该对象调用它的属性和方法。如下图所示:
在这里插入图片描述

  类和类之间都是自行产生其他类的对象来进行使用,好处是使用简单,需要的时候 new 就行。但是缺点就有很多,用到哪些类都需要自身去创建,依赖度太高,不利于解耦,也有可能多个类都使用一个类的对象,但要产生多个对象,不能“共享”,冗余过多。当有了 IoC/DI 的容器后,在客户端类中不再主动去创建这些对象了,所有对象的产生都交给了容器来实现,当需要对象时,在通过容器获取它就行。如下图所示:
在这里插入图片描述

二、Ioc 配置的方式

  众所周知,Spring设计的两个大的要点:IOC和AOP。从框架的设计角度而言,更为重要的是简化开发,比如提供更为便捷的配置Bean的方式,直至0配置(即约定大于配置)。

2.1 xml 配置

  顾名思义,就是将bean的信息配置xml文件里,通过Spring加载文件为我们创建bean。这种方式出现很多早前的SSM项目中,将第三方类库或者一些配置工具类都以这种方式进行配置,主要原因是由于第三方类不支持Spring注解。使用这种配置的优点是可以使用于任何场景,结构清晰、通俗易懂;当然其缺点也比较明显,就是配置繁琐、不易维护,枯燥无味且扩展性差。

<?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="userService" class="org.dllwh.springframework.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>
</beans>

2.2 Java 配置

  将类的创建交给我们配置的JavcConfig类来完成,Spring只负责维护和管理,采用纯Java创建方式。其本质上,就是把在XML上的配置声明转移到Java配置类中。这种方式适用于任何场景,配置方便,因为是纯Java代码,扩展性高,十分灵活。但由于是采用Java类的方式,声明不明显,如果大量配置,可读性比较差。
  实现这种配置,需要创建一个配置类, 添加 @Configuration 注解声明为配置类。然后创建方法,在方法上加上 @bean,该方法用于创建实例并返回,该实例创建后会交给spring管理,方法名建议与实例名相同(首字母小写)。

@Configuration
public class BeansConfig {

    @Bean("userDao")
    public UserDaoImpl userDao() {
        return new UserDaoImpl();
    }

    @Bean("userService")
    public UserServiceImpl userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao());
        return userService;
    }
}

2.3 注解配置

  通过在类上加注解的方式,来声明一个类交给 Spring 管理,Spring 会自动扫描带有 @Component@Controller@Service@Repository 这四个注解的类,然后帮我们创建并管理,前提是需要先配置Spring的注解扫描器。使用这种方式开发便捷,通俗易懂,方便维护。当然其具有局限性,对于一些第三方资源,无法添加注解,只能采用XML或JavaConfig的方式配置。如下所示:

@Service
public class UserServiceImpl {
    @Autowired
    private UserDaoImpl userDao;

    public List<User> findUserList() {
        return userDao.findUserList();
    }
}

一些常用的注解,包括但不限于产生对象、引入依赖、设置配置等,如下表所示:

名称解释
@Component启动 Spring 后,会自动把它转成容器管理的 Bean
@Repository用于对DAO层注解,但是目前该功能与 @Component 相同
@Service用于对业务层注解,但是目前该功能与 @Component 相同
@Controller用于对控制层注解,但是目前该功能与 @Component 相同
@Scope作用域,等同于 XML 中的 scope 写法例如: @Component(“guanwei”) @Scope(“prototype”)
@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的 bean 才会按 照类型来装配注入
@Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合 @Qualifier 一起使用
@Qualifier@Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了
@Configuration配置注解,标明当前类是一个配置类
@ComponentScan配置扫描那些包,一次可以扫描多个包
@Bean将方法的返回结果存放到 IoC 容器,就是手动产生对象并存放到 IoC 容器中
@Lazy设置当前类是否懒加载,配合产生对象注解使用

三、依赖注入的方式

常用的注入方式主要有三种:构造方法注入(Construct注入)、setter注入、基于注解的注入(接口注入)。

3.1 setter方式

  在XML配置方式中,property都是setter方式注入,比如下面的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="userService" class="org.dllwh.springframework.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>
</beans>

  本质上包含两步:第一步,需要 new UserServiceImpl() 创建对象,所以需要默认构造函数;第二步,调用 setUserDao() 函数注入 userDao 的值,所以需要 setUserDao() 函数。所以对应的service类是这样的:

public class UserServiceImpl {
    private UserDaoImpl userDao;

    public UserServiceImpl() {
    }

    public List<User> findUserList() {
        return this.userDao.findUserList();
    }

    public void setUserDao(UserDaoImpl userDao) {
        this.userDao = userDao;
    }
}

  而在注解和Java配置方式下:

public class UserServiceImpl {
    private UserDaoImpl userDao;

    public List<User> findUserList() {
        return this.userDao.findUserList();
    }

    @Autowired
    public void setUserDao(UserDaoImpl userDao) {
        this.userDao = userDao;
    }
}

  在 Spring 3.x 刚推出的时候,推荐使用注入的就是这种, 但是这种方式比较麻烦,所以在 Spring4 .x 版本中推荐构造函数注入。

3.2 构造函数

  在XML配置方式中,<constructor-arg> 是通过构造函数参数注入,比如下面的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="userService" class="tech.pdai.springframework.service.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>
</beans>

  本质上是new UserServiceImpl(userDao)创建对象,所以对应的service类是这样的:

public class UserServiceImpl {
    private final UserDaoImpl userDao;

    public UserServiceImpl(UserDaoImpl userDaoImpl) {
        this.userDao = userDaoImpl;
    }

    public List<User> findUserList() {
        return this.userDao.findUserList();
    }
}

  在注解和Java配置方式下

@Service
public class UserServiceImpl {
    private final UserDaoImpl userDao;

    @Autowired
    public UserServiceImpl(final UserDaoImpl userDaoImpl) {
        this.userDao = userDaoImpl;
    }

    public List<User> findUserList() {
        return this.userDao.findUserList();
    }
}

3.3 注解注入

  以@Autowired(自动注入)注解注入为例,修饰符有三个属性:Constructor、byType、byName,默认按照byType注入。

属性说明
constructor通过构造方法进行自动注入,spring会匹配与构造方法参数类型一致的bean进行注入。如果有一个多参数的构造方法,
一个只有一个参数的构造方法,在容器中查找到多个匹配多参数构造方法的bean,那么spring会优先将bean注入到多参数的构造方法中。
byName被注入bean的id名必须与set方法后半截匹配,并且id名称的第一个单词首字母必须小写,这一点与手动set注入有点不同。
byType查找所有的set方法,将符合符合参数类型的bean注入。

比如:

@Service
public class UserServiceImpl {
    @Autowired
    private UserDaoImpl userDao;

    public List<User> findUserList() {
        return userDao.findUserList();
    }
}

小结

  其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

在这里插入图片描述

  • https://www.pdai.tech/md/spring/spring-x-framework-ioc.html

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分辨率与像素

一 概念 分辨率: 分辨率指的是图像或显示器屏幕上可见的像素数量&#xff0c;通常以水平像素数和垂直像素数表示。例如&#xff0c;一个分辨率为1920x1080的屏幕意味着在水平方向上有1920个像素&#xff0c;在垂直方向上有1080个像素。分辨率决定了图像或屏幕上能够显示的细节…

神经网络反向传播算法

今天我们来看一下神经网络中的反向传播算法&#xff0c;之前介绍了梯度下降与正向传播~ 神经网络的反向传播 专栏&#xff1a;&#x1f48e;实战PyTorch&#x1f48e; 反向传播算法&#xff08;Back Propagation&#xff0c;简称BP&#xff09;是一种用于训练神经网络的算…

qt5-入门-2D绘图-Graphics View 架构

参考&#xff1a; Qt Graphics View Framework_w3cschool https://www.w3cschool.cn/learnroadqt/4mvj1j53.html C GUI Programming with Qt 4, Second Edition 本地环境&#xff1a; win10专业版&#xff0c;64位&#xff0c;Qt 5.12 基础知识 QPainter比较适合少量绘图的情…

蓝桥杯如何准备国赛?

目录 一、赛前准备 1、如何刷题&#xff0c;刷哪些题&#xff1f; 2、记录&#xff08;主要看个人习惯&#xff09; CSDN博客 写注释 3、暴力骗分 4、从出题人的角度出发&#xff0c;应该如何骗分 二、赛中注意事项 一、赛前准备 1、如何刷题&#xff0c;刷哪些题&…

Ubuntu 24.04安装搜狗输入法-解决闪屏问题

问题描述 在Ubuntu 24.04 LTS系统中按照官方安装指导《Ubuntu20.04安装搜狗输入法步骤》安装搜狗输入法后&#xff1a; 会出现屏幕闪烁&#xff0c;无法正常使用的问题&#xff1b;系统搜索框和gnome-text-editor无法使用搜狗输入法&#xff1b; 原因分析 闪屏可能是Ubuntu…

ESP32-C3第二路串口(非调试)串口打通(1)

1. 概述与引脚复用 《ESP32-C3 系列芯片技术规格书》中提到&#xff0c;ESP32-C3系列芯片中有两路串口。 第1路串口就是常用的调试串口&#xff0c;在笔者使用的ESP32-C3-DevKitC-02开发板中&#xff0c;这一路串口通过CP2102 USB转UART桥芯片与电脑的USB口相连接&#xff0c;…

c4d渲染动画只能渲染1帧怎么回事?c4d云渲染解决1秒停止

当您在C4D中尝试渲染动画时&#xff0c;如果只渲染出了一个静止的帧&#xff0c;这通常意味着您的设置中存在一些问题。动画本身是由一系列连续的静态图像&#xff08;帧&#xff09;组成的&#xff0c;如果只生成了一帧&#xff0c;那么显然是渲染设置出现了错误。为了解决这个…

如何利用快解析远程访问NAS、FTP、Web服务

什么是内网、外网&#xff1f; 所谓内网就是内部建立的局域网络或办公网络。一家公司或一个家庭有多台计算机&#xff0c;他们利用不同网络布局将这一台或多台计算机或其它设备连接起来构成一个局部的办公或者资源共享网络&#xff0c;我们就称它为内部网络&#xff0c;也叫内…

微服务之SpringCloud AlibabaSeata处理分布式事务

一、概述 1.1背景 一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用&#xff0c;就会产生分布式事务问题 but 关系型数据库提供的能力是基于单机事务的&#xff0c;一旦遇到分布式事务场景&#xff0c;就需要通过更多其他技术手段来解决问题。 全局事务&#xff1a;…

计算机网络4——网络层4内部路由选择协议

文章目录 一、有关路由选择协议的几个基本概念1、理想的路由算法2、分层次的路由选择协议 二、内部网关协议 RIP1、协议 RIP 的工作原理2、特点3、距离向量算法4、坏消息传播慢 三、内部网关协议 OSPF1、基本特点2、OSPF 的五种分组类型 本节将讨论几种常用的路由选择协议&…

【Mac】mac 安装 prometheus 报错 prometheus: prometheus: cannot execute binary file

1、官网下载 Download | Prometheus 这里下载的是prometheus-2.51.2.linux-amd64.tar.gz 2、现象 解压之后启动Prometheus 启动脚本&#xff1a; nohup ./prometheus --config.fileprometheus.yml > prometheus.out 2>&1 & prometheus.out日志文件&#xff…

【C++】:类和对象(下)

目录 一&#xff0c;再谈构造函数1.初始化列表2. 隐式类型转换的过程及其优化3. 隐式类型转换的使用4. explcit关键字5. 单参数和多参数构造函数的隐式类型转换 二&#xff0c;static成员1.静态成员变量2.静态成员函数 三&#xff0c;友元3.1 友元函数3.2 友元类 四&#xff0c…

Vue ui 创建vue项目,详细使用攻略。

1.安装及启动 1.1 Vue ui 使用前提是全局安装vue.js 命令如下 npm install vue -g 1.2 安装过Vue.js 之后 随便在自己系统的一个地方打开命令面板 1.3 使用命令启动vue ui面板创建项目 vue ui 如图运行后显示这种就是启动成功&#xff0c;成功之后会弹出页面或者直接访问你的…

QT5制做两个独立窗口

目录 增加第二个窗口 主窗口文件添加一个私有成员为子窗口 定义两个槽函数和 关联按钮和子窗口和主窗口 添加子窗口成员 子窗口处理函数 补充回顾 增加第二个窗口 1、 2、 3 主窗口文件添加一个私有成员为子窗口 在mainwidget.h文件 同时添加两个槽&#xff1b;来处理…

Visual studio 2019 编程控制CH341A芯片的USB设备

1、硬件 买了个USB可转IIC、或SPI、或UART的设备&#xff0c;主芯片是CH341A 主要说明USB转SPI的应用&#xff0c;绿色跳线帽选择IIC&SPI&#xff0c;用到CS0、SCK、MOSI、MISO这4个引脚 2、软件 2.1、下载CH341A的驱动 点CH341A官网https://www.wch.cn/downloads/CH34…

人工智能工具的强大之处:我用过的最好用的AI工具

人工智能工具的强大之处&#xff1a;我用过的最好用的AI工具 在当今科技迅速发展的时代&#xff0c;人工智能(AI)工具已经成为我们日常生活和工作中不可或缺的一部分。从语音助手到自动化内容创建工具&#xff0c;再到数据分析软件&#xff0c;AI的应用领域广泛且深远。本篇博…

【antd + vue】InputNumber 数字输入框 输入限制

一、需求说明 只能输入数字和小数点&#xff0c;保留小数点后两位&#xff1b;最多输入6位&#xff1b;删除所有内容时&#xff0c;默认为0&#xff1b; 二、问题说明 问题1&#xff1a;使用 precision 数值精度 时&#xff0c;超出规定小数位数时会自动四舍五入&#xff1b;…

LLM应用:让大模型prompt总结生成Mermaid流程图

生成内容、总结文章让大模型Mermaid流程图展示&#xff1a; mermaid 美人鱼, 是一个类似 markdown&#xff0c;用文本语法来描述文档图形(流程图、 时序图、甘特图)的工具&#xff0c;您可以在文档中嵌入一段 mermaid 文本来生成 SVG 形式的图形 Prompt 示例&#xff1a;用横向…

PDF 正确指定页码后,挂载的书签页码对不上

这个问题与我的另一篇中方法一样 如何让一个大几千页的打开巨慢的 PDF 秒开-CSDN博客 https://blog.csdn.net/u013669912/article/details/138166922 另做一篇原因是一篇文章附带一个与该文章主题不相关的问题时&#xff0c;不利于被遇到该问题的人快速搜索发现以解决其遇到的…

深度学习口型驱动Visemenet使用小结

说明 我前一篇博客《使用共振峰提取元音音素/从声音生成口型动画》探索了使用共振峰分析元音&#xff0c;然后从元音音素映射到视位的口型驱动方案。当时我就在想&#xff0c;如果能用深度学习法方法从音频直接生成音素流&#xff0c;然后转换成对应视位&#xff0c;不就很容易…