IOC源码解析

这篇具有很好参考价值的文章主要介绍了IOC源码解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

主要从3方面进行解析

Bean与BeanDefinition

容器初始化主要做的事情(主要脉络)

BeanFactory

ApplicationContext

模板方法模式

Resource、ResourceLoader、容器之间的关系

BeanDefinitionReader

BeanDefinition的注册

小结


  • 主要从3方面进行解析

    • 解析配置
    • 定位与注册对象
    • 注入对象
  • Bean与BeanDefinition

  • Bean是Spring的一等公民
    • Bean的本质就是java对象,只是这个对象的生命周期由容器来管理
    • 不需要为了创建Bean而在原来的java类上添加任何额外的限制(低侵入)
    • 对java对象的控制方式体现在配置上
    • Bean是一个由Spring IoC容器实例化、组装和管理的对象
    • Bean并不是程序员编辑的,而是程序运行时,由Spring通过反射生成的
  • 什么是BeanDefinition
    • 根据配置,生成用来描述Bean的BeanDefinition
    • BeanDefinition 是定义 Bean 的配置元信息接口
    • 包含:
    • Bean 的类名
    • 设置父 bean 名称、是否为 primary
    • Bean 行为配置信息,作用域、自动绑定模式、生命周期回调、延迟加载、初始方法、销毁方法等
    • Bean 之间的依赖设置,dependencies
    • 构造参数、属性设置
    • 例:
    • 作用范围scope(@Scope)
    • 懒加载lazy-init(@Lazy):决定Bean实例是否延迟加载
      • true:在使用bean实例的时候才会将bean实例创建出来
    • 首选primary(@Primary) :设置为true的bean会是优先的实现类
      • 当一个接口有多个实现类的时候,加了@Primary的bean会是优先的实现类
    • factory-bean和factory-method(@Configuration和@Bean)
      • factory-bean:工厂bean的名称
      • factory-method:工厂方法的名称
  • main执行,主要是从容器里面调用getBean,传入Bean的id,来获取实例对象
  • 不同的BeanId创建的实例都是不同的
  • 不管是xml还是注解的方式,bean对象都会被容器定位读取到内存,之后解析成一个个的beanDefinition实例注册到容器,整个过程发生在容器的初始化过程中
  • 容器初始化主要做的事情(主要脉络)

    IOC源码解析

  • Spring的Bean的继承关系不是通过extends和implements实现的,而是设置parent属性

    IOC源码解析

  • BeanDefinition:描述某个Bean实例的配置信息(延时加载,scope...)
  • AttributeAccessor:定义了最基本的对任意对象的元数据的修改或者获取方式,主要用于获取BeanDefinition的属性,并对这些属性进行操作
  • BeanMetadataElement:用来传输可配置的元对象 ,主要用于返回BeanDefinition这个class对象本身
  • AbstractBeanDefinition:定义了共有的构造函数,子类就可以基于构造函数给属性赋值,其次定义了一些通用属性的get和set方法,方便给通用的属性赋值,还提供了公用的工具方法
  • RootBeanDefinition:不能作为其他类的子类,通常用于在运行时接受多个BeanDefinition合并起来的信息;能接受具有继承关系的两个BeanDefinition的属性,承接两者合并在一起的除了parent属性之外的属性
  • GenericBeanDefinition:是通用的BeanDefinition实现,具有parentName属性,方便程序在运行时设置parentBeanDefinition
  • BeanFactory

  • BeanFactory与FactoryBean有什么区别?
    • BeanFactory是Spring容器的根接口,定义了Bean工厂的最基本的功能特性(比如根据BeanName获取Bean实例等)
    • 使用作管理Bean的容器,Spring中生成的Bean都是由这个接口的实现类管理的
    • FactoryBean也是接口,基于接口里面的getObject方法,用户可以生成一套复杂的逻辑来生成Bean
    • 它本质也是一个Bean,但他并不是注入到某个地方例如Service之类
    • 它的作用是用来生成普通的bean的,实现这个接口之后,Spring容器在初始化时会把实现了这个接口的bean取出来,使用Bean里面的getObject方法来生成我们想要的bean
  • 例子:
  • 配置bean,并测试得到bean实例

    IOC源码解析

  • IOC源码解析
  • 发现创建的并不是UserFactoryBean的实例,而是user实例
  • 说明直接调用UserFactoryBean的getBean方法,它会默认调用里面的getObject方法,返回创建的user实例
  • 那怎么获取UserFactoryBean的实例呢?
  • 只需要在前面添加一个&即可

    IOC源码解析

  • IOC源码解析
  • BeanFactory的重要方法:

    IOC源码解析

  • 简单容器

    IOC源码解析

  • 接口主要用来描述容器具有的功能,实现类实现功能
  • ListableBeanFactory:批量列出工厂生产的实例的信息(beanName)
  • ApplicationContext

  • 术语补充
    • 组件扫描:自动发现应用容器中需要创建的Bean
    • 自动装配:自动满足Bean之间的依赖(对被注解Autowired注解标记的成员变量进行依赖注入)
  • BeanFactory面向的是Spring自身,而ApplocationContext面向的是开发者
  • 好比Spring容器是一辆汽车,BeanFactory是一个汽车的发动机,而ApplicationContext则是一辆完整的汽车

    IOC源码解析

  • ApplicationContext:应用上下文,继承BeanFactory接口,它是Spring的一个更高级的容器,提供了更多的有用的功能
    • 国际化(MessageSource)
    • 访问资源,如URL和文件(ResourceLoader)
    • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
    • 消息发送、响应机制(ApplicationEventPublisher)
    • AOP(拦截器)
  • 因为他继承了多个接口所以拥有更多的功能
    • EnvironmentCapable:可以通过EnvironmentCapable里面的Environment getEnvironment();获取web.xml里面contextConfigLocation信息,根据它的值去加载Spring的所有的配置文件
    • ListableBeanFactory: 通过列表的方式管理bean
    • HierarchicalBeanFactory: 实现多层级的容器来实现对每一层bean的管理
    • ResourcePatternResolver: 加载资源文件
    • MessageSource: 管理message,进而实现国际化的功能
    • ApplicationEventPublisher:具备事件发布的能力,(容器在启动的时候会发布一些listener,用来监听发布的事件)监听机制
  • ApplicationContext常用容器
  • 传统的基于XML配置的经典容器
    • FileSystemXmlApplicationContext:从文件系统加载配置
    • ClassPathXmlApplicationContext:从classpath加载配置
    • XmIWebApplicationContext:用于Web应用程序的容器
  • 目前比较流行的容器
    • AnnotationConfigServletWebServerApplicationContext:在SpringBoot的Boot模块下
    • AnnotationConfigReactiveWebServerApplicationContext:用来满足响应式的需求
    • AnnotationConfigApplicationContext:对于普通的非web应用常用
  • ApplicationContext方法都是以get开头,都是只读的,需要使用子接口来实现ApplicationContext可配置的能力
  • 子接口ConfigurableApplicationContext:
    • 里面提供了一些方法来配置ApplicationContext,启动、刷新、关闭应用上下文的能力
    • 重新启动容器,清除缓存,重新装载类信息
  • AbstractApplicationContext:
    • 实现了ApplicationContext里面简单不易动的部分:容器工厂的处理,事件的发送广播、监听器的注册、容器初始化操作refresh方法、getBean方法
  • refresh()是Spring最核心的方法,在SpringApplication.run(args)的时候执行,是一个同步同步方法,用synchronized关键字来实现
  • refresh()大致功能
    • 容器初始化、配置解析
    • BeanFactoryPostProcessor和BeanPostProcessor的注册和激活
    • 国际化配置
  • 模板方法模式

  • 围绕抽象类,实现通用逻辑,定义模板结构,部分逻辑由子类实现
  • 基于继承的,会准备一个抽象类,将部分逻辑以具体方法和具体逻辑实现,然后定义一个模板结构,将剩下的具体内容延迟到子类去实现
  • 声明一些抽象方法迫使子类实现剩下的逻辑
  • 复用: 将相同逻辑的代码在父类中复用,将具体实现下沉到子类
  • 反向控制: 通过父类调用子类的操作,通过对子类具体的实现扩展出不同的行为,以此来实现反向控制
  • 通过子类扩展来实现定制化的行为,符合开闭原则

    IOC源码解析

  • 模板方法:定义了整个方法需要实现的业务的骨架
  • 具体方法:一些确定不变的逻辑,父类直接实现
  • 钩子:不是由子类来直接调用而是在特定条件发生时由抽象类的调用方来调用,以用于对发生的事件进行响应
  • 钩子就是供子类灵活变通的钥匙
  • 例如:去KTV唱歌,服务生帮忙打开音响,结束后客户付钱是统一必有的操作,所以在父类中实现,点歌需要看用户的需求,所以设置为抽象方法交给子类实现,但是会不会额外消费子类就看情况而定,选择性实现,定义为钩子方法

    IOC源码解析

  • refresh()方法就是一个模板方法,主要定义了容器启动时需要做的事情,其中方法:

    IOC源码解析

  • Resource、ResourceLoader、容器之间的关系

  • java中资源会被抽象成url,解析url的protocol处理不同协议资源
  • 而Spring将物理资源抽象为Resource
  • Resource
    • 一个接口,定义了资源的基本操作

      IOC源码解析

    • InputStreamSource:只有一个方法,获取资源流
    • Resource家族:

      IOC源码解析

    • 针对不同的资源有不同类的实现;每个实现类代表资源的访问策略
    • EncodedResource:对资源文件的编码处理
    • AbstractResource:对Resource方法的大部分默认公共实现;若想自定义Resource可继承它,覆盖相应方法即可
    • ServletContextResource:访问web容器中的上下文资源而实现的,支持以流、url的形式访问,还可以从jar包中访问资源
    • ClassPathResource:访问类加载路径下的资源;可自动搜索WEB-INF/classes下的资源
    • FileSystemResource:访问文件系统资源;java提供的File类也可实现
    • 会根据资源地址自动选择正确的Resource
    • 强大的加载资源的方式
    • 自动识别"classpath:"、”file:" 等资源地址前缀
    • 支持自动解析Ant风格带通配符的资源地址
    • Ant
    • 路径匹配表达式,用来对URI进行匹配;类似于正则表达式,只不过正则表达式表示的范围比较广,Ant只适用于路径匹配
    • ? 匹配任何单字符
    • *匹配0或者任意数量的字符
    • **匹配0或者更多的目录
    • 例子:

      IOC源码解析

  • Resourceloader
    • 实现不同的Resource加载策略,按需返回特定类型的Resource
    • 是一个接口,根据路径获取资源;可以是classPath或者file等

      IOC源码解析

  • DefaultResourceLoader
    • 简单工厂模式侧重的是:返回创建出的对象,用户不了解对象本身,相当于黑盒
    • 但是策略模式要求用户了解策略本身,即针对什么样的资源使用什么样的Resource加载

      IOC源码解析

    • 因为Resourceloader里面的方法只能获取一个resource实例,因此又来了一个接口ResourcePatternResolver

      IOC源码解析

    • 实现类PathMatchingResourcePatternResolver去实现,同时还支持Ant路径风格模式
    • Spring提供了Resource和ResourceLoader来统一抽象整个资源及其定位,使得资源与资源的定位有了更加清晰的界限,并且有DefaultResourceLoader使得自定义实现更加清晰和方便
    • 发现ApplicationContext继承了 ResourcePatternResolver 那就间接继承了ResourceLoader
    • 所以任何的ApplicationContext的实现都可以看做 ResourcePatternResolver 或ResourceLoader的实例
    • 整个ApplicationContext 的实现类完全可以支持ResourcePatternResolver 、ResourceLoader,这也是高级容器为什么支持统一加载资源的原因
    • 在容器读取配置时,委派给了PathMatchingResourcePatternResolver以及DefaultResourceLoader来执行
  • BeanDefinitionReader

  • 它是ResourceLoader的使用者,是资源加载利器的使用者
  • 它利用ResourceLoader、ResourcePatternResolver,将配置信息解析成一个个BeanDefinition,并借助BeanDefinitionRegistry将BeanDefinition注册到容器里
  • 作用:
  • 定义了一系列加载BeanDefinition的接口,针对单个或者多个配置文件的加载,或者单个resource实例或者多个resource实例的加载,最终目的将配置文件的配置转换成一个个的BeanDefinition

    IOC源码解析

  • 体系结构:

    IOC源码解析

  • AbstractBeanDefinitionReader
    • 实现了BeanDefinition的公共逻辑
    • 如果是ResourcePatternResolver的实例,则代表需要加载多个资源
    • 不管是加载单个还是多个资源,最后都会调用loadBeanDefinitions方法做进一步加载
    • loadBeanDefinitions():主要根据用户提供的资源加载器的类型来判断加载单个或多个资源
    • 实现类是针对不同的资源类型做定义的
  • XmlBeanDefinitionReader
    • 传入指定xml文件的路径,XmlBeanDefinitionReader 调用它的父类ResourceLoader根据传入的路径返回resoure实例,它再去调用loadBeanDefinitions方法去执行

      IOC源码解析

  • BeanDefinition的注册

    IOC源码解析

  • 方法:
  • 1---向注册表中注册一个新的BeanDefinition实例

    IOC源码解析

  • 2---移除注册表中已存在的实例

    IOC源码解析

  • 3---从注册表中取得指定的BeanDefinition实例

    IOC源码解析

  • 4---判断BeanDefinition实例是否在注册表中(是否注册)

    IOC源码解析

  • DefaultListableBeanFactory实现了 BeanDefinitionRegistry接口

    IOC源码解析

  • 同时里面定义的beanDefinitionMap将注册的beanName为key,注册实例为value存里面

    IOC源码解析文章来源地址https://www.toymoban.com/news/detail-475996.html

  • 配置到读取到加载到解析
  • 主要的逻辑就是将解析的beanDefinition的实例给注册到DefaultListableBeanFactory容器(里面的beanDefinitionMap)中
  • 注解容器是先于xml文件创建出来的,为什么要提前创建出来呢?
  • 因为他会提前创建出一些系统内置的beanDefinition实例,所以就需要提前在构造函数中创建DefaultListableBeanFactory实例,以提供对系统内置的beanDefinition的注册
  • 先加载内置的beanDefinition实例,再加载entrance(被Component放到容器里的bean)
  • 再加载其他被注解(Controller、Service....)修饰的类
  • 在容器刷新的时候被注册进来,和xml配置一样都是在容器刷新的时候被注册进来
  • BeanDefinitionRegistryPostProcessor的beanDefinition会被优先执行,普通的BeanFactoryPostProcessor会被延后执行
  • 执行BeanDefinitionRegistryPostProcessor会调用invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry)
  • 执行完之后才会调用invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);去执行普通的BeanFactoryPostProcessor
  • 小结

  • Spring会依据BeanDefinition创建Bean
  • DefaultListableBeanFactory:主要负责对BeanDefinition的注册
  • 容器刷新时的共性:都使用了AbstractApplicationContext里面的refresh()
  • 配置资源在Spring里面会被转换成一个个不同的Resource对象实例,这离不开ResourceLoader的支持
  • 有了ResourcePatternResolver使得Spring可以根据配置资源的ur路径选择合适的resource进行包装,体现了策略模式
  • 有了好的利器,BeanDefinitionReader进行使用
  • xml资源被XmlBeanDefinitionReader解析成Document对象,再委托给BeanDefinitionDocumentReader解析成一个个GenericBeanDefinition实例,再将其注册到DefaultListableBeanFactory内置容器中
  • 不同于xml,xml所有的beanDefinition实例都是在refresh()方法中刷新时注册的,而注解分为三类BeanDefinition的注册
  • 第一类:容器内部设置的BeanDefinition实例,在容器的构造函数一经调用就被注册到内置容器中
  • 第二类:用户自定义的带有@Configuration的类,在容器的构造函数中调用register()方法时被注册
  • 第三类:常规的BeanDefinition则是在refresh()方法里的容器级别后置处理器被调用时,进行注册的
  • AnnotatedBeanDefinitionReader:负责对上述三种类型的BeanDefinition进行解析,并将其注册到DefaultListableBeanFactory容器中

到了这里,关于IOC源码解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring专题】Spring之Bean的生命周期源码解析——阶段二(二)(IOC之属性填充/依赖注入)

    由于Spring源码分析是一个前后联系比较强的过程,而且这边分析,也是按照代码顺序讲解的,所以不了解前置知识的情况下,大概率没办法看懂当前的内容。所以,特别推荐看看我前面的文章(自上而下次序): Spring底层核心原理解析【学习难度: ★★☆☆☆ 】 手写简易

    2024年02月12日
    浏览(39)
  • YOLOv5源码逐行超详细注释与解读(1)——项目目录结构解析

    前面简单介绍了YOLOv5的网络结构和创新点(直通车:【YOLO系列】YOLOv5超详细解读(网络详解)) 在接下来我们会进入到YOLOv5更深一步的学习,首先从源码解读开始。 因为我是纯小白,刚开始下载完源码时真的一脸懵,所以就先从最基础的 项目目录结构 开始吧~因为相关解读

    2024年02月03日
    浏览(52)
  • 软件进行验收测试的必要性体现在哪些方面?

    在软件开发的过程中,验收测试是一个非常重要的环节。为确认软件是否符合预期需求而进行的一种测试工作。目的是验证软件是否满足其预期功能、性能以及质量等要求。通过对软件进行全面、系统的测试,可以发现和解决软件开发过程中存在的问题和缺陷,确保软件的质

    2024年02月09日
    浏览(48)
  • nginx通过配置文件来进行的安全方面优化

    目录 1、隐藏版本号 2、配置错误页面重定向 3、添加header防止XSS攻击 4、利用referer图片防盗链 5、拒绝某些user-agent 6、限制HTTP请求方法 7、nginx开启https 8、控制迸发连接数 说明: 由于某些 Nginx 漏洞只存在于特定的版本,隐藏版本号可以提高安全性。 Nginx隐藏版本信息配置示

    2024年02月08日
    浏览(43)
  • FastJson在Java后端方面解析使用(二)

    ​ JSON现在常用来做前后端数据交互,两个蝴蝶飞只是简单的对JSON做一下讲解和简单使用。关于JSON,我还了解的远远不够。由于本人经验有限,嘴皮子不溜,所以学术性,概念性,底层性的知识点暂时不做介绍。文章中有错误之处,欢迎拍砖和指点。在此,特别向阿里团队表

    2024年02月12日
    浏览(33)
  • 论文AIGC总体疑似度:从七个方面深入解析

    随着人工智能技术的不断发展,AIGC检测已经成为学术界和产业界广泛应用的工具。论文的AIGC总体疑似度,即使用AIGC技术对论文整体内容的原创性进行检测的结果,是评估论文质量的重要依据。本文将从七个方面对论文AIGC总体疑似度进行深入解析。 aigc过高怎么办?利用更高

    2024年02月21日
    浏览(56)
  • Spring IOC 源码分析

    ​ IoC (Inversion of control ) 控制反转。它是一种思想不是一个技术实现。描述的是: Java 开发领域对象的创建以及管理的问题。 例如:现有类 A 依赖于类 B 。传统的开发方式 :往往是在类 A 中手动通过 new 来 new 一个 B 的对象出来使用 IoC 思想的开发方式 :不通过 ne

    2024年02月02日
    浏览(45)
  • Spring IOC 源码解读

    将回答以下问题: BeanFactory 和 ApplicationContext 之间的关系和区别。 一个 Bean 是如何被注入到 IOC 容器里,中间经历了什么过程(Bean 的生命周期)。 假设你已经有如下经验: 什么是 IOC。 don‘t call us, we‘ll call you - 好莱坞原则 依赖查找和依赖注入。 依赖查找是 IOC 容器中的对

    2024年02月02日
    浏览(36)
  • 对CentOS7进行账户和登录方面的安全加固

    一、用户账户安全加固 1、修改用户密码策略 2、锁定或删除系统中与服务运行运维无关的用户 (1)查看系统中的用户并确定无用的用户 more /etc/passwd (2)锁定不使用的账户(锁定或删除用户根据自己的需求操作即可) 锁定不使用的账户: usermod -L username 或删除不使用的账

    2024年02月04日
    浏览(38)
  • Linux推出Debian 12.1,并进行多方面系统修复

    据了解,Debian是最古老的 GNU / Linux 发行版之一,也是许多其他基于 Linux 的操作系统的基础,包括 Ubuntu、Kali、MX 和树莓派 OS 等。 此外,该操作系统以稳定性为重,不追求花哨的新功能,因此新版本的发布往往需要很长时间。早在今年 6 月初,Debian 12“bookworm”发布,而日前

    2024年02月15日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包