Spring重温之IOC解密

在一开始学习 Spring 的时候,我们就接触 IoC 了,作为 Spring 第一个最核心的概念,我们在解读它源码之前势必需要对其有深入的认识,本篇为【死磕 Spring】系列博客的第一篇博文,主要介绍 IoC 基本概念和各个组件。

  1. IoC 理论
    IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。

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

谁控制谁
控制什么
为何是反转
哪些方面反转了
在回答这四个问题之前,我们先看 IoC 的定义:

所谓 IoC ,就是由 Spring 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);

}

}
这就是我们通常做事的方式,如果我们需要某个对象,一般都是采用这种直接创建的方式(new BeautifulGirl()),这个过程复杂而又繁琐,而且我们必须要面对每个环节,而且使用完成之后我们还要复杂销毁它,这种情况下我们的对象与它所依赖的对象耦合在一起。

其实我们需要思考一个问题?我们每次用到自己依赖的对象真的需要自己去创建吗?我们知道,我们依赖对象其实并不是依赖该对象本身,而是依赖它所提供的服务,只要在我们需要它的时候,它能够及时提供服务即可,至于它是我们主动去创建的还是别人送给我们的,其实并不是那么重要。再说了,相比于自己千辛万苦去创建它还要管理善后而言,直接有人送过来是不是显得更加好呢?

这个给我们送东西的”人” 就是 IoC,在上面的例子中,它就相当于一个婚介公司,作为一个婚介公司它管理着很多男男女女的资料,当我们需要一个女朋友的时候,直接跟婚介公司提出我们的需求,婚介公司则会根据我们的需求提供一个妹子给我们,我们只需要负责谈恋爱,生猴子就行了。你看,这样是不是很简单明了。

诚然,作为婚介公司的 IoC 帮我们省略了找女朋友的繁杂过程,将原来的主动寻找变成了现在的被动接受,更加简洁轻便。你想啊,原来你还得鞍马前后,各种巴结,什么东西都需要自己去亲力亲为,现在好了,直接有人把现成的送过来,多么美妙的事情啊。所以,简单点说,IoC 的理念就是让别人为你服务,如下图(摘自Spring揭秘):

201805071001
201805071001

在没有引入 IoC 的时候,被注入的对象直接依赖于被依赖的对象,有了 IoC 后,两者及其他们的关系都是通过 Ioc Service Provider 来统一管理维护的。被注入的对象需要什么,直接跟 IoC Service Provider 打声招呼,后者就会把相应的被依赖对象注入到被注入的对象中,从而达到 IoC Service Provider 为被注入对象服务的目的。所以 IoC 就是这么简单!原来是需要什么东西自己去拿,现在是需要什么东西让别人(IoC Service Provider)送过来

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

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

可能你比较牛逼,刚刚出生的时候就指腹为婚了。
大多数情况我们还是会考虑自己想要什么样的妹子,所以还是需要向婚介公司打招呼的。
还有一种情况就是,你根本就不知道自己想要什么样的妹子,直接跟婚介公司说,我就要一个这样的妹子。
1.1 注入形式
所以,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 方式注入会显得比较宽松灵活些,它可以在任何时候进行注入(当然是在使用依赖对象之前),这就好比你可以先把自己想要的妹子想好了,然后再跟婚介公司打招呼,你可以要林志玲款式的,赵丽颖款式的,甚至凤姐哪款的,随意性较强。

③ 接口方式注入

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

感兴趣的胖友,可以看看 《依赖注入的三种实现形式 —— 接口注入(Interface Injection)》

1.2 推荐文章
关于 IoC 理论部分,笔者不在阐述,这里推荐几篇博客阅读:

《谈谈对 Spring IoC 的理解》
《Spring 的 IoC 原理[通俗解释一下]》
《Spring IoC 原理(看完后大家可以自己写一个spring)》
2. 各个组件
先看下图(摘自:http://singleant.iteye.com/blog/1177358)

组件类图
组件类图

该图为 ClassPathXmlApplicationContext 的类继承体系结构,虽然只有一部分,但是它基本上包含了 IoC 体系中大部分的核心类和接口。

下面我们就针对这个图进行简单的拆分和补充说明。

2.1 Resource 体系
org.springframework.core.io.Resource,对资源的抽象。它的每一个实现类都代表了一种资源的访问策略,如 ClassPathResource、RLResource、FileSystemResource 等。

Spring重温之IOC解密

Resource 类图

2.1.2 ResourceLoader 体系
有了资源,就应该有资源加载,Spring 利用 org.springframework.core.io.ResourceLoader 来进行统一资源加载,类图如下:

Spring重温之IOC解密

ResourceLoader 类图

关于 Resource 和 ResourceLoader 的源码解析,见 《【死磕 Spring】—— IoC 之 Spring 统一资源加载策略》 。

2.2 BeanFactory 体系
org.springframework.beans.factory.BeanFactory,是一个非常纯粹的 bean 容器,它是 IoC 必备的数据结构,其中 BeanDefinition 是它的基本结构。BeanFactory 内部维护着一个BeanDefinition map ,并可根据 BeanDefinition 的描述进行 bean 的创建和管理。

Spring重温之IOC解密
BeanFactory 类图

BeanFactory 有三个直接子类 ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory 。
DefaultListableBeanFactory 为最终默认实现,它实现了所有接口。
2.3 BeanDefinition 体系
org.springframework.beans.factory.config.BeanDefinition ,用来描述 Spring 中的 Bean 对象。

BeanDefinition 类图

Spring重温之IOC解密

BeanDefinition 类图

2.4 BeanDefinitionReader 体系
org.springframework.beans.factory.support.BeanDefinitionReader 的作用是读取 Spring 的配置文件的内容,并将其转换成 Ioc 容器内部的数据结构 :BeanDefinition 。

Spring重温之IOC解密
BeanDefinitionReader 类图

2.5 ApplicationContext 体系
org.springframework.context.ApplicationContext ,这个就是大名鼎鼎的 Spring 容器,它叫做应用上下文,与我们应用息息相关。它继承 BeanFactory ,所以它是 BeanFactory 的扩展升级版,如果BeanFactory 是屌丝的话,那么 ApplicationContext 则是名副其实的高富帅。由于 ApplicationContext 的结构就决定了它与 BeanFactory 的不同,其主要区别有:

继承 org.springframework.context.MessageSource 接口,提供国际化的标准访问策略。
继承 org.springframework.context.ApplicationEventPublisher 接口,提供强大的事件机制。
扩展 ResourceLoader ,可以用来加载多种 Resource ,可以灵活访问不同的资源。
对 Web 应用的支持。
下图来源:https://blog.csdn.net/yujin753/article/details/47043143

Spring重温之IOC解密
ApplicationContext 类图

2.6 小结
上面五个体系可以说是 Spring IoC 中最核心的部分,后面博文也是针对这五个部分进行源码分析。其实 IoC 咋一看还是挺简单的,无非就是将配置文件(暂且认为是 xml 文件)进行解析(分析 xml 谁不会啊),然后放到一个 Map 里面就差不多了,初看有道理,其实要面临的问题还是有很多的,下面就劳烦各位看客跟着 LZ 博客来一步一步揭开 Spring IoC 的神秘面纱。

此系列博文为 LZ 学习、研究 Spring 机制和源码的学习笔记,会涉及参考别人的博文和书籍内容,如有雷同,纯属借鉴,当然 LZ 会标明参考来源。同时由于知识面和能力的问题,文章中难免会出现错误之处,如有,望各位大佬指出,不胜感激。

另外,通过上面五个体系,我们可以看出,IoC 主要由 spring-beans 和 spring-context 项目,进行实现

欢迎大家加入我得个人公众号,大家一起学习沟通交流

Spring重温之IOC解密

声明:整篇文章转载自知识星球,里面有完善的Spring解密系列,大家如果平常想重新温习这些知识点,是一个很不错的地方

Spring重温之IOC解密

Original: https://www.cnblogs.com/qiuzhiqiang/p/16022534.html
Author: 邱志强
Title: Spring重温之IOC解密

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/570540/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • MySQL实现表之间的字段更新

    新功能写好之后,需要把以前表数据更新一下,字段数据从以前的表中获取,只更新两个字段 UPDATE TABLE1,TABLE2 SET TABLE1.COLUMN1 = TABLE2…

    Java 2023年6月8日
    067
  • SimpleDateFormat线程不安全的5种解决方案

    1.什么是线程不安全? 线程不安全也叫非线程安全,是指多线程执行中,程序的执行结果和预期的结果不符的情况就叫着线程不安全。 线程不安全的代码 SimpleDateFormat 就是…

    Java 2023年5月30日
    083
  • idea内置tomcat中java代码热更新

    按照上图设置后,然后修改代码后按shift+F9快捷键,即可实现代码更新,这时在debug模式下会看到代码变更后的输出 Original: https://www.cnblogs….

    Java 2023年5月29日
    079
  • redis删除缓存时遇到的问题

    一、redis查询key的方式 redis常用两种方式用于key的精确/模糊匹配 1. KEYS pattern keys pattern用于匹配pattern所有key,会返回当…

    Java 2023年6月13日
    0102
  • SpringCloud : 多个 @FeignClient 注解 value 设置为同一个应用的解决方案

    Feign 版本10.1.0 Spring 版本 5.1.5.RELEASE SpringBoot 版本 2.1.5.RELEASE SpringCloud 版本 2.1.1.RE…

    Java 2023年5月30日
    071
  • 部署jar包windows服务工具

    背景 某个周末一个线上项目因为服务器自动重启导致了系统挂了,我们是通过jenkins部署的jar包所以需要手动重启项目,解决问题后准备调换部署方式让项目随系统自动启动,试用tomc…

    Java 2023年6月15日
    088
  • 浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配、环境标识

    浅尝Spring注解开发,基于Spring 4.3.12包含自定义扫描组件、自定义导入组件、手动注册组件、自动注入方法和参数、使用Spring容器底层组件等 告诉Spring这是一…

    Java 2023年6月5日
    092
  • python闭包和装饰器

    本文目录: 闭包的解析和用法 函数式装饰器 类装饰器 一、闭包 闭包是一种函数,从形式上来说是函数内部定义(嵌套)函数,实现函数的扩展。在开发过程中,考虑到兼容性和耦合度问题,如果…

    Java 2023年6月14日
    066
  • redis分析系列之set命令

    前言 最近研究下redis源码,现在从最基本的命令行操作来分析,redis是如何处理命令操作的 redis的set命令操作 我们在redis-cli执行下面的命令 java;gut…

    Java 2023年6月5日
    087
  • 谈谈Raft

    本文主要参考: 极客时间-etcd 实战课 GitChat-分布式锁的最佳实践之:基于 Etcd 的分布式锁 谈到分布式协调组件,我们第一个想到的应该是大名鼎鼎的Zookeeper…

    Java 2023年6月5日
    065
  • Java架构师-十项全能学习笔记(1)

    Java架构师-十项全能学习笔记(1) @Configuration @EnableStateMachine public class OrderStateMachineConfi…

    Java 2023年6月7日
    071
  • Python定时任务,三步实现自动化

    大家好,我是小一 今天的文章源自于工作中的一个小技巧,主要是涉及到日常工作的自动化处理。 如果说你每天都需要做一些重复的工作,比如出一份报告、统计一个数据、发一封邮件等等 那你完全…

    Java 2023年6月7日
    069
  • java基础篇—-多态的使用

    我们都知道面向对象的三大特征:封装,继承,多态.封装就是,给属性提供公开的get,set方法,把具有相同功能的重复的代码抽取出来,形成一个方法;继承使用extends关键字,子类可…

    Java 2023年6月8日
    092
  • 不同标准下的C语言常量范围的默认类型的检测 (测试样例为C90与C99)

    不同标准下的C语言常量范围的默认类型的检测 一、 C90与C99标准下的不同常量范围的默认类型 *C90标准下对不同常量范围默认类型的检测实现及运行结果: C9 9 *标准下对不同…

    Java 2023年6月5日
    066
  • Spring Boot 日志各种使用姿势,是时候捋清楚了!

    @ 1. Java 日志概览 1.1 总体概览 1.2 日志级别 1.3 综合对比 1.4 最佳实践 2. Spring Boot 日志实现 2.1 Spring Boot 日志配…

    Java 2023年5月30日
    065
  • mybatis中的#和$的区别

    将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by &#8220…

    Java 2023年5月30日
    078
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球