【java】Spring Boot -- Spring的IOC实现原理

news2024/12/23 23:38:19

文章目录

  • IOC定义
  • 理解IOC
  • 不使用IOC:
  • 使用IOC:
  • 使用IOC的好处
  • IOC提供被依赖对象的方式
    • 构造器注入
    • setter 方法注入
    • 接口方式注入
  • 简单模拟IOC
  • 总结

IOC定义

IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
Spring IOC容器通过xml,注解等其它方式配置类及类之间的依赖关系,完成了对象的创建和依赖的管理注入。实现IOC的主要设计模式是工厂模式。
在这里插入图片描述

如何理解“控制反转”好呢?理解好它的关键在于我们需要回答如下四个问题:

  • 谁控制谁
  • 控制什么
  • 为何是反转
  • 哪些方面反转了

IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

理解IOC

以年轻小伙子找女朋友为例子来说明IOC的作用:

/**
 * 年轻小伙子
 */
public class YoungMan {
    private BeautifulGirl beautifulGirl;

    YoungMan(){
        // 可能你比较牛逼,指腹为婚
        // beautifulGirl = new BeautifulGirl();
    }

    public void setBeautifulGirl(BeautifulGirl beautifulGirl) {
        this.beautifulGirl = beautifulGirl;
    }

    public static void main(String[] args){
        YoungMan you = new YoungMan();
        BeautifulGirl beautifulGirl = new BeautifulGirl("你的各种条件");
        beautifulGirl.setxxx("各种投其所好");

        // 然后你有女票了
        you.setBeautifulGirl(beautifulGirl);
    }
}

不使用IOC:

小伙子需要: new BeautifulGirl() ,也就是自己去创建一个女朋友对象。这个过程复杂而又繁琐,而且我们必须要面对每个环节,同时使用完成之后我们还要负责销毁它。

使用IOC:

小伙子自己不用去找女朋友,反过来找IOC,IOC就相当于一个婚介公司,它管理着很多男男女女的资料,小伙子直接跟婚介公司提出需求,婚介公司则会根据需求提供一个妹子给我们,我们只需要负责使用它就行了。

所以,简单点说,IoC 的理念就是让别人为你服务

可以理解为: IOC主动把妹子注入给想使用它的小伙子。 (调用的时候使用Autowied ,这个对象就是前文说的bean, 通过注册进入IOC容器,被实例化之后再进入IOC容器的bean缓存池,就可以供程序调用了,这就和bean的生命周期连了起来。)

  • 通过IOC的注册机制可以保证对象的安全性和合规性;

  • 实例化对象只需要实例化一次,即可进入IOC容器的bean缓存池,降低了对象的创建开销,提高了程序的性能(有点类似单例);

  • 应用程序调用对象从bean缓存池获取,这样是秒获取对象,提高了调用对象的速度。

现在来回答上面那四个问题,答案就显得非常明显了:

  1. 谁控制谁:在传统的开发模式下,我们都是采用直接 new 一个对象的方式来创建对象,也就是说你依赖的对象直接由你自己控制,但是有了 IOC 容器后,则直接由 IoC 容器来控制。所以“谁控制谁”,当然是 IoC 容器控制对象。
  2. 控制什么:控制对象。
  3. 为何是反转:没有 IoC 的时候我们都是在自己对象中主动去创建被依赖的对象,这是正转。但是有了 IoC 后,所依赖的对象直接由 IoC 容器创建后注入到被注入的对象中,依赖的对象由原来的主动获取变成被动接受,所以是反转。
  4. 哪些方面反转了:所依赖对象的获取被反转了。

使用IOC的好处

  • 集中管理,实现类的可配置和易管理。
  • 降低了类与类之间的耦合度。

IOC提供被依赖对象的方式

IOC Service Provider 为被注入对象提供被依赖对象也有如下几种方式:构造方法注入、stter方法注入、接口注入。

构造器注入

构造器注入,顾名思义就是被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。

YoungMan(BeautifulGirl beautifulGirl){
        this.beautifulGirl = beautifulGirl; //这里可以定义很多女孩的条件
}

构造器注入方式比较直观,对象构造完毕后就可以直接使用,这就好比你出生你家里就给你指定了你媳妇。

setter 方法注入

对于 JavaBean 对象而言,我们一般都是通过 getter 和 setter 方法来访问和设置对象的属性。所以,当前对象只需要为其所依赖的对象提供相对应的 setter 方法,就可以通过该方法将相应的依赖对象设置到被注入对象中。如下:

public class YoungMan {
    private BeautifulGirl beautifulGirl;

    public void setBeautifulGirl(BeautifulGirl beautifulGirl) {
        this.beautifulGirl = beautifulGirl;
    }
}

相比于构造器注入,setter 方式注入会显得比较宽松灵活些,它可以在任何时候进行注入(当然是在使用依赖对象之前),这就好比你可以先把自己想要的妹子想好了,然后再跟婚介公司打招呼,随意性较强。

一般程序中会使用这种方法进行实例化。

接口方式注入

接口方式注入显得比较霸道,因为它需要被依赖的对象实现不必要的接口,带有侵入性。一般都不推荐这种方式。

简单模拟IOC

public interface BeanFactory {
    Object getBean(String id);  
}

public class ClassPathXmlApplicationContext implements BeanFactory {
    //容器,用来存放注入的Bean  
    private Map<String, Object> container = new HashMap<String, Object>();  

    //解析xml文件,通过反射将配置的bean放到container中  
    public ClassPathXmlApplicationContext(String fileName) throws Exception{  
        SAXBuilder sb = new SAXBuilder(); 

        Document doc 
        =sb.build(ClassPathXmlApplicationContext.class.getResource("/"+fileName));
       
        Element root = doc.getRootElement();  
        List<Element> list = XPath.selectNodes(root, "/beans/bean");  

        for (int i = 0; i < list.size(); i++) {              
           Element bean = list.get(i);  
           String id = bean.getAttributeValue("id");  
           String clazz = bean.getAttributeValue("class");  
           Object o = Class.forName(clazz).newInstance();  
           container.put(id, o);  
          }  
    }
    @Override  
    public Object getBean(String id) {        
        return container.get(id);  
    }  

}

需要导入 jdom.jar包。

<?xml version="1.0" encoding="UTF-8"?>  
<beans>  
  <bean id="people" class="com.ioc.People" />  
  <bean id="chicken" class="com.ioc.Chicken" />  
  <bean id="dog" class="com.ioc.Dog" />  
</beans>  
public interface Animal {
     void say();  
}
public class Dog implements Animal {
    @Override
    public void say() {
         System.out.println("汪汪"); 
    }
}
public class Chicken implements Animal {
    @Override
    public void say() {
        System.out.println("鸡你很美");  
    }
}
public class People {
    public void info(){
        System.out.println("小明-23岁");
    }
}
public static void main(String[] args) throws Exception {  

        //加载配置文件  
        BeanFactory f = new ClassPathXmlApplicationContext("applicationContext.xml");  

        Object os = f.getBean("dog");  
        Animal dog = (Animal)os;  
        dog.say();  

        Object op = f.getBean("chicken");  
        Animal chicken = (Animal)op;  
        chicken.say();  

        Object p = f.getBean("people");  
        People people= (Animal)p;  
        people.info();  
    } 

总结

A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起。

而使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。

所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。

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

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

相关文章

【Selenium】十分钟手把手带你学会WebDriver API

目录 1、定位元素【8种】 2、操作测试对象 3、添加等待 4、弹窗类型 5、浏览器的操作 6、键盘事件 7、选择框 8、上传文件 1、定位元素【8种】 元素定位是自动化测试的核心&#xff0c;想要去操作一个对象&#xff0c;第一步就是需要我们先去识别这个对象。每个对象就会…

全民ChatGPT热:快来解锁你的“全能网友”

前 言 2021年11月30日&#xff0c;OpenAI推出人工智能聊天原型ChatGPT&#xff0c;赚足了眼球&#xff0c;在AI界引发了类似AIGC让艺术家失业的大讨论。 据报道&#xff0c;ChatGPT在开放试用的短短几天&#xff0c;就吸引了超过 100 万互联网注册用户。并且社交网络流传出各种…

html5标签

图片&#xff1a;image 主要属性&#xff1a; src&#xff1a;源属性的值是图像的 URL 地址。 alt&#xff1a;用来为图像定义一串预备的可替换的文本。 注意事项&#xff1a; 注意: 假如某个 HTML 文件包含十个图像&#xff0c;那么为了正确显示这个页面&#xff0c;需要加…

速通Spring

尚硅谷2023最新版Spring6课程_bilibili 1 Spring 【强制】Spring是什么&#xff1f; 1) Spring是一款主流的Java EE轻量级开源框架。 轻量级&#xff1a;体积很小&#xff0c;且不需要依赖于其他组件。 2) 狭义的Spring。 Spring Framework。 3) 广义的Spring。 以Spring F…

python对多个csv文件进行合并(表头需一致)

之前写过python对【多个Excel文件】中的【单个sheet】进行合并&#xff0c;参考&#xff1a;点我 之前也写过python对【多个Excel文件】中的【多个sheet】进行合并&#xff0c;参考&#xff1a;点我 今天再写一个python对多个csv格式的文件进行合并的小工具 但是大家切记&am…

GIS开源框架:ArcGIS文件地理数据库(GDB)解析与入库

对于GIS专业毕业的同学&#xff0c;想必对于ArcGIS软件不会太陌生&#xff0c;对于地理数据库也有一定的了解和使用经验。但是&#xff0c;撇开软件操作层面不谈&#xff0c;作为一个WebGIS/GIS开发人员&#xff0c;我们如何通过GIS开源框架去完成地理数据库的自动化解析和入库…

解决不同影像裁剪后栅格数据行列不一致问题

前言在处理栅格数据时&#xff0c;尽管用同一个矢量文件裁剪栅格数据&#xff0c;不同数据来源的栅格行列数也会出现不一致的情况。如果忽略或解决不好&#xff0c;会导致后续数据处理出现意想不到的误差或错误&#xff0c;尤其是利用编程实现数据处理时。因此&#xff0c;应当…

VisualGDB 5.6R9 FOR WINDOWS

Go cross-platform with comfort VisualGDB 是 Visual Studio 的一个非常强大的扩展&#xff0c;它允许您调试或调试嵌入式系统。这个程序有一个非常有吸引力的用户界面&#xff0c;它有许多调试或调试代码的功能。VisualGDB 还有一个向导可以帮助您调试程序&#xff0c;为您提…

【C++】关键字、命名空间、输入和输出、缺省参数、函数重载

C关键字(C98)命名空间产生背景命名空间定义命名空间使用输入&输出缺省参数什么叫缺省参数缺省参数分类函数重载函数重载概念C支持函数重载的原理--名字修饰C关键字(C98) C总计63个关键字&#xff0c;C语言32个关键字。 下面我们先看一下C有多少关键字&#xff0c;不对关键…

Linux 解压JAR包 查看class内容

快速解决方案 查询class相对路径&#xff1a;jar tf test.jar | grep "test.class"单独解压class文件&#xff1a;jar xvf test.jar com/test/test.class查看class文件内容&#xff1a;javap -c com/test/test.class 背景 服务运行后&#xff0c;日志打印出来发现…

【taichi】利用 taichi 编写深度学习算子 —— 以提取右上三角阵为例

本文以取 (bs, n, n) 张量的右上三角阵并展平为向量 (bs, n*(n1)//2)) 为例&#xff0c;展示如何用 taichi 编写深度学习算子。 如图&#xff0c;要把形状为 (bs,n,n)(bs,n,n)(bs,n,n) 的张量&#xff0c;转化为 (bs,n(n1)2)(bs,\frac{n(n1)}{2})(bs,2n(n1)​) 的向量。我们先写…

各种素材网站大全【全部倾倒,福利倒计时-JS,HTML,游戏素材,UI,图片素材等

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;解忧杂货铺 ⭐各种素材网站大全⭐ 文章目录⭐各种素材网站大全⭐&#x1f3b6;大家必逛的四大天王…

STM32F769BIT6微控制器STM32F769IGT6详细规格

说明STM32F7 32 位 MCUFPU 基于高性能的 ARMCortex-M7 32 位 RISC 内核&#xff0c;工作频率高达 216MHz。Cortex-M7 内核具有单浮点单元(SFPU)精度&#xff0c;支持所有 ARM 单精度数据处理指令与数据类型。同时执行全套 DSP 指令和存储保护单元&#xff08;MPU&#xff09;&a…

JVM02类加载子系统

1. 加载阶段 通过一个类的全限定名获取定义此类的二进制字节流 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构 在内存中生成一个代表这个类的java.lang.Class对象&#xff0c;作为方法区这个类的各种数据的访问入口 加载class文件的方式 从本地系统中直接…

六、HTTP 首部字段

HTTP 首部字段 一、HTTP 报文首部 HTTP 请求报文由方法、URI、HTTP 版本、HTTP 首部字段等部分构成。 HTTP 响应报文由HTTP版本、状态码&#xff08;数字和原因短语&#xff09;、HTTP首部字段3部分构成。 HTTP 协议的请求和响应报文中必定包含 HTTP 首部。首部内容为客户端…

TensorRT如何工作

TensorRT如何工作 本章提供了有关 TensorRT 工作原理的更多详细信息。 文章目录TensorRT如何工作5.1. Object Lifetimes5.2. Error Handling and Logging5.3 Memory5.3.1. The Build Phase5.3.2. The Runtime Phase5.4. Threading5.5. Determinism5.1. Object Lifetimes Tenso…

ChatGPT通俗导论:从RL之PPO算法、RLHF到GPT-N、instructGPT

前言 自从我那篇BERT通俗笔记一经发布&#xff0c;然后就不断改、不断找人寻求反馈、不断改&#xff0c;其中一位朋友倪老师(之前我司NLP高级班学员现课程助教老师之一)在谬赞BERT笔记无懈可击的同时&#xff0c;给我建议到&#xff0c;“后面估计可以尝试尝试在BERT的基础上…

MACD多周期共振指标公式,日周月共振

有人问多周期MACD怎么写&#xff0c;编写指标的难度其实不大&#xff0c;主要问题是解决多周期MACD显示的问题。日线、周线、月线三个周期&#xff0c;每个周期都有快线DIF和慢线DEA两条线&#xff0c;一共6条&#xff0c;怎么在副图上清晰显示出来。 一、MACD多周期共振指标公…

第三章SpringBoot配置文件

文章目录什么是配置文件比如我们的QQ的配置文件配置文件作用SpringBoot配置文件的格式Spring Boot 配置文件主要分为以下两种格式properties 配置文件说明properties 基本语法properties 缺点分析yml 配置文件yml概述yml基础语法读取配置文件Value 注解使用“${}”的格式读取Co…

深度使用国产Bg-Tinkle数据库客户端—太赞了,居然还集成chatGPT AI生成SQL

软件概述数据库客户端软件是一种用于连接、管理和操作数据库的软件。它通常与数据库管理系统&#xff08;DBMS&#xff09;配合使用&#xff0c;允许用户在其上执行SQL 语句、浏览数据库中的数据、执行备份和恢复操作以及执行其他管理任务。常见的数据库客户端软件包括 MySQL W…