首页 > 其他分享 >IoC容器趣谈

IoC容器趣谈

时间:2023-10-02 12:22:24浏览次数:34  
标签:容器 趣谈 name Boy age IoC public

今天我们来谈谈Spring的内核之一——IoC容器

大家可能会有这样的疑问:

”这玩意为啥要叫容器呢?好奇怪“

”容器不是装东西的吗?难道IoC容器也是用来装什么东西的?“

有上述两个想法的小伙伴,我觉得你们是非常聪明的,并且平时有思考的习惯。别着急,让我们慢慢往下看

IoC容器的两大重要概念

IoC理解

​ IoC(Inverse of Control)控制反转,是应用本身不再进行对象的创建和维护工作,而是将这些工作交给外部容器去进行,这样控制权转移给外部容器,反转了。

举个例子:假设你和女朋友打算出去旅游,准备自驾去西藏玩。女朋友让你做旅游攻略,以及沿途行程安排。你本以为这是一件容易的事情,但实际操作后你抱怨道:“md,这比我该bug还麻烦”

刚好这时候,手机上推来一条“*西藏小团8人游,珠峰下的星空,只需要2XXX...*”的消息。这下爽了,研究一下直接报团,一下子省去了许多步骤,你开始幻想美丽的旅途...

思路回来一下,这个过程就很形象的描述了控制反转,你对旅游 (对象) 的控制权交给了旅行社 (容器) 。

DI理解

​ DI(Dependency Injection) 依赖注入指组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。 依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

还拿上述例子举例,当你把你的旅游计划告诉给你好久不见,外地工作 的好朋友。你朋友听完之后也十分心动呀,说想带着他女朋友也一起去。

“那正好一起呀,人多大家玩的开心”。于是你把链接推给你的好朋友,让他也购买你这个旅行团,于是你们现在是一个旅行团,并且可以一起玩喽

你和你的朋友逻辑上是有关系的,可是不在一个地方,又想在一起玩。于是进入同一个旅行社(容器),当你们在西藏开始玩的时候(运行期),你们就可以见面了。

说白了,就是对象不用你创建了,他们之间的关系你也别管了。

所以:IoC容器 = IoC(控制反转)+DI(依赖注入)

这就是为什么spring框架在整个项目中有“大管家”的称号了

对于上面两个概念理解清楚了,其实就IoC容器你已经快“吃透”了。但是光有概念还不行,我们还得有细节和操作

创建IoC容器的方式

有以下两种常用的方式:

//创建IoC容器 利用ApplicationContext的子类ClassPathXmlApplicationContext(方式一)
ClassPathXmlApplicationContext ioc =
        new ClassPathXmlApplicationContext("ioc.xml");
//方式二 利用ApplicationContext的子类FileSystemXmlApplicationContext
       FileSystemXmlApplicationContext ioc2 =
                new FileSystemXmlApplicationContext("D:\\code\\SpringDemo\\src\\main\\resources\\ioc.xml");

从代码中可以看出,主要区别在于配置文件.xml的路径上,绝对路径和项目路径

其实还有两种方式也可以用于IoC容器的创建:

  • AnnotationConfigApplicationContext
    

    直接加载上下文定义(仅限基于Java配置类使用)不使用XML文件,使用注解

  • XmlWebApplicationContext
    

    读取Web应用下的XML配置文件并加载上下文定义 用于web项目里

那么我们在深挖一下,上述两个子类中都有ApplicationContext的字样,那这个应该也是个类,是怎么来的呢?

下面代码模拟其中原理

//通过BeanFactory类创建ApplicationContext容器
// 加载配置文件
        ClassPathResource resource = new ClassPathResource("applicationContext.xml");
        
        // 创建BeanFactory容器
        BeanFactory beanFactory = new XmlBeanFactory(resource);
        
        // 从容器中获取对象实例
        MyBean myBean = (MyBean) beanFactory.getBean("myBean");
        
        // 使用对象实例
        myBean.doSomething();

原来是利用了BeanFactory这个类。其实ApplicationContext,它是 BeanFactory 的子类,更好的补充并实现了 BeanFactory 的。

网上查了资料,BeanFactory类似于Hashmap,键值对中分别装了对象的名称对象 (这里的对象被称为bean 马上讲到)但它一般只有 get, put 两个功能,所以称之为“低级容器”。

ApplicationContext 多了很多功能,因为它继承了多个接口,可称之为“高级容器”。

下面的图片可以很好的对他们的关系进行理解

img

装配bean

刚才提到了一个名称 bean ,我用“对象”一词对他进行转义。

其实bean就是包装好了的对象(Object),Java本身是面向对象编程语言,任何操作都是围绕作者对象进行,在这里,由spring对其进行封装。

那装配bean又是什么意思?有点像给枪上子弹的感觉

装配bean就是在IoC容器中创建bean 以及确定bean和bean之间的依赖关系

Spring支持三种装配bean的方式

  • 基于XML配置
  • 基于注解
  • 基于Java类配置

首先来看第一种,建立一个ioc.xml配置文件:

<!--创建Boy bean 相当于(Boy boy = new Boy())-->
<bean id="boy" class="ioc.Boy" /> 

<!--又创建Girl bean 相当于(Girl girl = new Girl)-->
<bean id="Girl" class="ioc.Girl"/>

第二种,通过注解:

依赖注入的方法

  • 方法注入(推荐)
  • 构造器注入
  • 接口注入

注意:spring只支持前两种方式

看看下面男孩和女孩配对的例子 :

package ioc;

public class Boy {
    private String name;
    private int age;
    private Girl girl;

    public Boy() {
        System.out.println("实例化boy");
    }

    public Boy(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Boy(Girl girl) {//构造器注入(方式一)
        this.girl = girl;
    }

    public Boy(String name, int age, Girl girl) {
        this.name = name;
        this.age = age;
        this.girl = girl;
        System.out.println("构造器注入");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {//方法注入(方式二)
        this.girl = girl;
        System.out.println("方法注入girl");
    }

    @Override
    public String toString() {
        return "Boy{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

上述例子中我们定义了一个男孩类,男孩的属性为name,age,Girl(配对的女孩) ,女孩类的定义如下:

package ioc;

public class Girl {
    private String name;
    private int age;

    public Girl() {
        System.out.println("实例化girl");
    }

    public Girl(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

传统来说我们会通过这种方式来设置属性和构造依赖关系

Boy boy = new Boy("张三",25,new Girl("小美",22))

但现在,我们会在ioc.xml文件中写(方法注入):

<bean id="Girl" class="ioc.Girl">
    <!--相当于调用 setName("小美")-->
	<property name = "name" value = "小美"/>
    <property name = "age" value = "22"/>
</bean>
    

<!--创建Boy bean 相当于(Boy boy = new Boy())-->
    <!--init-method设置初始化值 destroy-method用于销毁ioc-->
    <bean id="boy" class="ioc.Boy" > 
        <!--给类的属性设置初始值-->
        <property name="name" value="张三"/>
        <property name="age" value="25"/>
        <!--依赖注入(方法注入) 相当于调用了setGirl(girl)-->
        <property name="girl" ref="Girl" />
    </bean>

上述的是方法注入,还有一种spring支持的 构造器注入 如下:

<bean id="Girl" class="ioc.Girl">
    <!--相当于调用 setName("小美")-->
	<property name = "name" value = "小美"/>
    <property name = "age" value = "22"/>
</bean>

<bean id="boy2" class="ioc.Boy" scope="prototype">
    <constructor-arg value="李四"/>
    <constructor-arg value="24"/>
    <!--依赖注入(构造器注入)-->
    <constructor-arg ref="Girl"/>
</bean>

注:构造器注入需要相应的构造器来进行

后续结果

通过上述的控制翻转和依赖注入,我们相当于完成了对象的设置,现在需要通过将我们输入的东西展示出来,代码如下:

package ioc;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TestIoC {
    public static void main(String[] args) {
        //创建IoC容器(方式一)
        ClassPathXmlApplicationContext ioc =
                new ClassPathXmlApplicationContext("ioc.xml");

        //方式二
//        FileSystemXmlApplicationContext ioc2 =
//                new FileSystemXmlApplicationContext("D:\\code\\SpringDemo\\src\\main\\resources\\ioc.xml");
//        System.out.println("ioc2"+ioc2);

        //获取IoC容器 的 Bean实例 (Boy对象实例)
/       Boy boy = (Boy) ioc.getBean("boy");
        System.out.println("boy:"+boy);

      
        Boy boy2 = (Boy) ioc.getBean("boy2");
        System.out.println("boy2:"+boy2);
        System.out.println(boy2.getGirl());

    }
}

打印结果:

boy:Boy{name='张三', age=25}
boy2:Boy{name='李四', age=24}
Girl{name='小美', age=22}

额外提一嘴,getBean()有两种用法:name: bean的id ;class:bean的类型(容器内唯一)

具体怎么玩呢?请听下回分解

标签:容器,趣谈,name,Boy,age,IoC,public
From: https://www.cnblogs.com/meloo/p/17739850.html

相关文章

  • springIoC
    IoC(控制反转):应用程序的依赖对象不自己创建和维护,交由统一的外部容器来创建和维护。这样控制权就由应用转移到外部容器。DI(依赖注入):通过IoC容器动态的向某个对象提供他需要的其他对象。 1..IoC容器的四种创建方式:ClassPathXmlApplicationContext:从项目的根目录下加载配置文件......
  • C++ STL标准容器的特点和典型的使用场景
    概念和作用C++标准模板库(StandardTemplateLibrary,STL)提供了一组通用的模板类和函数,用于处理常见的数据结构和算法。STL中的标准容器是其中的重要组成部分,它们提供了不同的数据结构和操作方式,适用于各种不同的使用场景。说白了,就是每一种容器代表一种特定的数据结构。我们在学C......
  • 颠覆性的Spring IOC
    一、什么是SpringIOC?SpringIOC(InversionofControl,控制反转)是Spring框架的核心概念之一,也是Spring框架实现轻量级和解耦的关键。IOC的基本思想是将对象的创建、依赖关系的管理、对象的生命周期等任务交给容器来完成,而不是由开发者手动管理。在传统的程序开发中,对象的创建和......
  • Python笔记:基本数据结构(容器)的优化
    列表的性能问题队列的弹出问题利用Python的原生语法很难写出一个真正完全能达到\(O(1)\)的队列,究其原因是由于insert方法的时间复杂度问题:classqueue: def__init__(self,q): self.q=[] defpopright(self): self.q.pop() defappendleft(self,elem): self.q.ins......
  • 16. Docker容器监控CAdvisor+InfluxDB+Granfana
    目录1、前言2、原始命令3、CAdvisor+InfluxDB+Granfana3.1、什么是CAdvisor3.2、什么是Influxdb3.3、什么是Granfana4、安装使用4.1、安装influxdb4.2、安装CAdvisor4.3、安装Granfana4.4、访问Influxdb4.5、创建CAdvisor数据库4.6、访问CAdvisor4.7、Grafana配置1、前言容器监控方......
  • HarmonyOS非线性容器特性及使用场景
     非线性容器实现能快速查找的数据结构,其底层通过hash或者红黑树实现,包括HashMap、HashSet、TreeMap、TreeSet、LightWeightMap、LightWeightSet、PlainArray七种。非线性容器中的key及value的类型均满足ECMA标准。HashMapHashMap可用来存储具有关联关系的key-value键值对集......
  • Dockerfile 语法详解:构建定制化容器镜像的基石
    Docker已经成为现代应用程序开发和部署的关键工具之一。在Docker的世界中,Dockerfile是一个至关重要的文件,它定义了如何构建容器镜像的步骤和配置。本文将深入探讨Dockerfile的语法,为您提供构建定制化容器镜像的基础知识。Dockerfile的基本结构Dockerfile是一个纯文本文件,其......
  • 探析Spring容器内部事件发布
    其实在JDK中已经提供相应的自定义事件发布功能的基础类:java.util.EventObject类:自定义事件类型java.util.EventListener接口:事件的监听器首先了解几个概念:Spring事件类结构1.事件类事件类也就是定义发送的内容,比如可以通过继承ApplicationContextEvent来自定义一......
  • HarmonyOS线性容器特性及使用场景
    线性容器实现能按顺序访问的数据结构,其底层主要通过数组实现,包括ArrayList、Vector、List、LinkedList、Deque、Queue、Stack七种。线性容器,充分考虑了数据访问的速度,运行时(Runtime)通过一条字节码指令就可以完成增、删、改、查等操作。ArrayListArrayList即动态数组,可用来构造全局......
  • STL容器的适用情况和缺点
    一.各种容器的特性vector序列容器,C++标准严格要求次容器的实现内存必须是连续的,唯一可以和标准C兼容的stl容器,任意元素的读取、修改具有常数时间复杂度,在序列尾部进行插入、删除是常数时间复杂度,但在序列的头部插入、删除的时间复杂度是O(n),可以在任何位置插入新元素,有随机访问功能,......