IOC源码解析

news2024/11/26 0:30:40

目录

主要从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实例注册到容器,整个过程发生在容器的初始化过程中
  • 容器初始化主要做的事情(主要脉络)

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

  • 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实例

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

  • BeanFactory的重要方法:

  • 简单容器

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

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

  • 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的注册和激活
    • 国际化配置
  • 模板方法模式

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

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

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

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

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

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

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

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

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

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

    • 实现类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

  • 体系结构:

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

  • BeanDefinition的注册

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

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

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

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

  • DefaultListableBeanFactory实现了 BeanDefinitionRegistry接口

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

  • 配置到读取到加载到解析
  • 主要的逻辑就是将解析的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容器中

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

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

相关文章

EMNLP -- Call for Main Conference Papers

以下内容链接:Call for Main Conference Papers - EMNLP 2023 目录 审核流程: 与 ARR 的交叉提交政策 注意: 注意: 重要日期 强制性摘要提交 提交方向 论文提交信息 论文提交和模板 确认 长论文 短文 贡献 演示模式 著作权 引用与…

Vue设计记事本

项目描述 项目实现功能有&#xff1a;记录今天要完成的任务&#xff0c;勾选已经完成的任务&#xff0c;删除已经完成的全部任务。 界面展示&#xff1a; 代码展示 创建一个Myitem.vue文件夹 <template><li><label ><input type"checkbox"…

机器学习 监督学习 Week2

Lib01 多变量线性回归 依旧是房价预测&#xff0c;但这次引入了多个变量&#xff0c;不仅仅只有房屋面积影响着房价&#xff0c;依旧尝试使用梯度下降算法找到最优的【w,b】&#xff0c;并且习惯使用向量点乘运算提高效率 import copy, math import numpy as np import matplot…

微内核和大内核

微内核和大内核是操作系统内核的两种不同设计思路。 图片来源 微内核 微内核是指将操作系统内核中的核心功能&#xff08;如进程管理、内存管理、设备驱动等&#xff09;作为独立进程运行&#xff0c;各进程间通过IPC(进程间通信)进行通讯。其中微内核相当于一个消息中转站&…

华为OD机试真题B卷 Java 实现【数据最节约的备份方法】,附详细解题思路

一、题目描述 有若干个文件&#xff0c;使用刻录光盘的方式进行备份&#xff0c;假设每张光盘的容量是500MB。 求使用光盘最少的文件分布方式&#xff0c;所有文件的大小都是整数的MB&#xff0c;且不超过500MB&#xff0c;文件不能分隔、分卷打包。 二、输入描述 每组文件…

AD PCB元器件封装设计方法

元器件封装界面 1.元器件可以新建PCB元件库&#xff0c;然后在新建的库中添加 2.也可以采用随便右键某个库中的元器件&#xff0c;选择“Edit…”&#xff0c;进入到元器件封装绘制界面。 元器件封装设计步骤 1.点击菜单栏工具——新的空元件&#xff1b;或者直接点击 Add&a…

认识.Net MAUI跨平台框架

.NET MAUI概念: 全称: .NET 多平台应用 UI (.NET MAUI) 是一个开源的跨平台框架&#xff0c;前身是Xamarin.Forms ! 用于使用 C# 和 XAML 创建本机移动和桌面应用。 NET MAUI&#xff0c;共享代码库,可在 Android、iOS、macOS 和 Windows 上运行的应用 应用架构: github 地址…

MySQL主从复制(概念和作用、实战、常见问题和解决办法、扩展、GTID同步集群、集群扩容、半同步复制)

文章目录 1. 主从复制1.1 概念和作用1.2 主从复制的步骤1.3 搭建主从同步&#xff08;配置步骤&#xff09;1.3.1 配置master主库1.3.2 配置slave从库1.3.3 主从复制的问题和解决方法1.3.4 MySQL主从复制监控和管理、测试 1.4 主从同步扩展1.4.1 主库同步与部分同步&#xff08…

【面试】操作系统面试题

操作系统面试题一 什么是操作系统&#xff1f;请简要概述一下 操作系统是管理计算机硬件和软件资源的计算机程序&#xff0c;提供一个计算机用户与计算机硬件系统之间的接口。 向上对用户程序提供接口&#xff0c;向下接管硬件资源。 操作系统本质上也是一个软件&#xff0…

Clion开发STM32之OTA升级模块(最新完整版)

前言 程序分为上位机部分、BootLoader、App程序上位机程序使用的是C#进行开发&#xff0c;目前只做成控制台部分开发环境依然选择Clion芯片采用的是stm32f103vet6升级模块已和驱动层逻辑进行分离 BootLoader程序 Flash分区定义 头文件 #ifndef STM32F103VET6_PROJECT_APP_FL…

图论-图的基本概念与数据结构

图的基本概念 无向图 边是没有方向的&#xff0c;也就是双向的 结点 V { v 1 , v 2 , . . . , v 7 } \mathcal{V} \{ v_1,v_2,...,v_7\} V{v1​,v2​,...,v7​} 边 ε { e 1 , 2 , e 1 , 3 , . . . , e 6 , 7 } \varepsilon \{e_{1,2},e_{1,3},...,e_{6,7}\} ε{e1,2​…

【面试】计算机网络面试题

计算机网络面试题一 简述OSI七层协议 OSI七层协议包括&#xff1a;物理层&#xff0c;数据链路层&#xff0c;网络层&#xff0c;运输层&#xff0c;会话层&#xff0c;表示层&#xff0c; 应用层 简述TCP/IP五层协议 TCP/IP五层协议包括&#xff1a;物理层&#xff0c;数据…

IntelliJ IDEA使用Alibaba Java Coding Guidelines编码规约扫描插件

代码规范和编码规约扫描插件使用 为什么要有代码规范&#xff1f;1.代码规范插件2.idea插件安装3.插件使用介绍编码规约扫描使用编码规约扫描结果 4.扫描结果严重级别BlockerCriticalMajor 5.《阿里巴巴Java开发手册&#xff08;终极版&#xff09;》 为什么要有代码规范&#…

HTTPS协议深入理解

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 目录 文章目录 一、HTTPS协议的由来及概念 二、加密是什么 三、HTTPS的工作流程 3.1 使用对称密钥 3.2 引入非对称加密 3.3 中间人攻击 3.4 引入证书 一、HTTPS协议的由来及概念 HTTPS 也是…

【chatGPT4结对编程】chatGPT4教我做图像分类

开始接触深度学习 大语言模型火了之后&#xff0c;我也想过是否要加入深度学习的行业当中来&#xff0c;一开始的想法就是AI大模型肯定会被各大厂垄断&#xff0c;我们作为普通应用型软件工程师直接调用api就完事&#xff0c;另外对自己的学历也自卑(刚刚够线的二本&#xff0…

2.4. 封装与访问控制

封装&#xff08;Encapsulation&#xff09;是面向对象编程的一个核心概念&#xff0c;它意味着将数据&#xff08;属性&#xff09;和方法&#xff08;操作数据的函数&#xff09;捆绑在一起&#xff0c;形成一个类&#xff08;Class&#xff09;。封装的目的是将数据和操作数…

C++插件管理类(下)——实际项目(阉割版)

文章目录 一、背景二、代码结构三、两个CMakeLists.txt3.1 父目录3.2 子目录src 四、代码实例4.1 main.cpp4.2 Plugin.h4.3 Plugin.cpp4.4 Comm.h4.5 calc.cpp 五、 踩坑点 一、背景 请参考C插件管理类(上) 二、代码结构 三、两个CMakeLists.txt 3.1 父目录 #设置cmake的最…

stackqueue的模拟实现

stack模拟&#xff1a; stack的源代码&#xff1a; stack的全部源代码就这些。 stack的代码少&#xff0c;原因在于采用了适配器模式&#xff0c;所谓适配器&#xff0c;以电器为例&#xff0c;每个电器都有电源适配器&#xff0c;中国的家用电源为220V的交流电&#xff0c;但是…

3d虚拟主播形象能提升提升企业销售额

随着科技的不断进步和发展&#xff0c;虚拟人形象正在被广泛地应用于商业宣传中。3D虚拟人形象是指采用计算机图形学、人工智能等技术&#xff0c;模拟真实人类形象的虚拟形象。相比于传统产品营销方式&#xff0c;采用3D虚拟人形象进行产品交互讲解对提升企业销售额具有很多优…

JavaWeb12(实现基础分页模糊查询的分页)

目录 一. 效果预览 ​编辑 二. 实现基本分页 2.1 分页sql --每页3条 取第二页 --由于伪列不能作用与大于符号也不能作用于between....and --因此需要将伪列----->名列 2.2 万能公式 2.3 首页&上一页&下一页实现 ②前端代码 2.4 末页实现&优化 ①底层代…