从根儿上学习spring 七 之run方法启动第四段(1)

news2024/9/30 0:28:45

图1

一步一步我们转眼间来到了第四部分,这是spring最核心的部分包含了bean的整个生命周期过程,不过大家不用担心如果内容过长我会分多个小节来说明以防止一篇文章让大家看晕看累难以吸收理解。让我们直接进入正题。

我们先进入图1的refreshContext方法看看它是如何刷新上下文对象的。该方法主要调用了AbstractApplicationContext#refresh执行刷新逻辑,我们直接看refresh方法。

图2

由图2可以看到refresh方法就是纯粹的调用了很多方法来完成刷新,我们先从第11行prepareBeanFactory(beanFactory);方法开始,因为前两个方法没什么逻辑大家自己点进去看下。

图3

从图3我们看出prepareBeanFactory(beanFactory)方法内部就是调用了beanFactory的一些方法来设置它的内部属性,分别调用了以下一些方法,至于设置的属性细节我们后面用到了再说,不然很多类的逻辑就够用一两篇文章单独来说了。

setBeanClassLoader

   设置当前应用类加载器

setBeanExpressionResolver

   设置表达式解析器,如el表达式解析器

addPropertyEditorRegistrar:

   向beanFactory中添加PropertyEditorRegistry。这里我稍微解释下PropertyEditor,PropertyEditorRegistry,PropertyEditorRegistrar三者的关系。

PropertyEditor:是bean属性编辑器,可以将字符串类型的值转换成其他类型,比如xml里配置的bean属性为字符串但数据类型却可以是Integer,可以通过PropertyEditor来做类型转换

PropertyEditorRegistry:是PropertyEditor的注册表用于维护PropertyEditor,所有的PropertyEditor都要注册在PropertyEditorRegistry里进行维护及使用

PropertyEditorRegistrar: 作用很简单,就是为了把PropertyEditor注册到PropertyEditorRegistry中

addBeanPostProcessor

   添加bean后置处理器---BeanPostProcessor用于bean的生命周期过程中给开发者提供对bean的功能扩展,简单来说就是在bean初始化前后你可以拿到bean对象做些你想做的。该后置处理器有两个方法,分别是postProcessBeforeInitialization---bean初始化前执行及postProcessAfterInitialization---bean初始化后执行,这里的“初始化”指的是执行InitializingBean接口的afterPropertiesSet方法前后。

ignoreDependencyInterface

   该方法是将不需要注入的接口类型进行打标,简单的说就是你不想对这接口类型进行依赖注入,像spring中的ApplicationContextAware就不能依赖注入。

registerResolvableDependency

   该方法是将不会通过自动注入方式注入到spring中的类放到Map, Object> resolvableDependencies属性里,在其他bean需要注入这些类的时候spring会先根据类型到resolvableDependencies属性里查找能找到就返回对应的对象,不然就通过beanFactory.getBean()方法去spring容器创建bean并返回。

setTempClassLoader

   添加临时类加载器,特殊场景时使用

registerSingleton

  向beanFacory中注册实例化好的bean对象,spring会向容器里预先注册spring内部的一些实例对象。

接着看图2postProcessBeanFactory(beanFactory);方法

     该方法允许你对beanFactory进行后置处理也就是对beanFactoty进行一些额外设置和操作。该方法主要由applicationContext的子类实现,我们当前启动的是AnnotationConfigServletWebServerApplicationContext子类它的postProcessBeanFactory(beanFactory)实现是向beanFactory中添加了beanPostProcessor后置处理器WebApplicationContextServletContextAwareProcessor。

    该后置处理器负责在bean初始化之前(这里的初始化也是指的是在执行InitializingBean的afterPropertiesSet方法)判断bean有没有实现ServletContextAware接口,对实现了该接口的bean调用其setServletContext方法设置ServletContext对象。

   其他的applicationContext实现子类对postProcessBeanFactory(beanFactory)方法的实现这里就不做分析了感兴趣的同学自行分析下吧,我们接着往下看。

接着看图2 invokeBeanFactoryPostProcessors(beanFactory)方法

   它会调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())方法执行所有的BeanFactoryPostProcessor接口的postProcessBeanFactory方法。          PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法的逻辑准确来说的话就是执行了了两个接口的两个方法,分别是BeanFactoryPostProcessor接口的postProcessBeanFactory方法和BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,执行顺序是先执行前者再执行后者。

   接口BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,从它的命名就可以看出它的作用是对BeanDefinitionRegistry进行后置处理,那么什么是BeanDefinitionRegistry呢?它是维护BeanDefinition的地方,所有的BeanDefinition都会被注册到BeanDefinitionRegistry中,通过它你可以获取所有的BeanDefinition或者向其再添加额外的BeanDefinition或者修改对应的BeanDefinition。

   因为可以通过BeanDefinitionRegistry新增新的beanDefinition,那么也就是通过BeanDefinitionRegistry我们可以向spring中再添加新的BeanFactoryPostProcessor的beanDefinition,从而间接添加新的BeanFactoryPostProcessor接口实现。所以这也是spring安排BeanDefinitionRegistryPostProcessor接口方法在BeanFactoryPostProcessor方法前执行的原因。

  既然BeanDefinitionRegistryPostProcessor是对BeanDefinitionRegistry做后置处理的,那是不是我们写的业务bean对应的BeanDefinition是不是就是在这里被加载到BeanDefinitionRegistry中的呢?答案是肯定的,这里有个特殊的BeanDefinitionRegistryPostProcessor就是ConfigurationClassPostProcessor它会把我们的启动类作为一个配置类来处理读取启动类上的 注解信息并找到我们定义的class位置加载为BeanDefinition,该类的具体逻辑请移步另一篇文章:BeanDefinitionRegistryPostProcessor解析

     在执行BeanFactoryPostProcessor接口时spring提供了执行顺序机制,分别通过PriorityOrdered接口和Ordered接口实现,PriorityOrdered继承了Ordered。spring会优先执行实现了PriorityOrdered接口的BeanFactoryPostProcessor,执行顺序是根据Ordered接口的getOrder方法返回值越小优先级越高。

    然后再获取只实现了Ordered接口的BeanFactoryPostProcessor,一样使用Ordered的getOrder方法返回值来比较大小,返回值越小优先级越大。

以防内容过多导致大家看的头晕,这节我们就先到这。下节继续

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

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

相关文章

PEX实验

一、kickstart自动安装脚本制作 1.关闭本机dhcp服务 2.安装图形化生成kickstart自动安装脚本的工具 3.配置http服务 下载httpd 启动并挂载 3.启动图形制作工具 system-config-kickstart 4.配置ks.cfg 5.拷贝到/var/www/html/中去 6.浏览器测试 配置dhcp服务 测试 二.搭建pex…

【JVM基础11】——垃圾回收-说一下JVM的分代回收?

目录 1- 引言:分代回收1-1 什么是分代回收(What)1-2 为什么要用分代回收?(Why) 2- ⭐核心:分代回收工作机制2-1 工作机制2-2 MinorGC、Mixed GC、FullGC的区别是什么 3- 总结3-1 说一下 JVM 的分…

【Java 第三篇章】注释、数据类型、运算符

一、注释 Java 中的注释有三种方式:单行注释、多行注释、文档注释。 1、单行注释语法 // 这是单行注释2、多行注释 /** 这是多行注释*/3、文档注释 /*** 这是文档注释*/二、数据类型 Java 中有 8 中基本数据类型,分别为:整型(b…

数据结构实验报告-排序

桂 林 理 工 大 学 实 验 报 告 一、实验名称 实验8 排序 二、实验内容&#xff1a; 分别采用直接插人排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序等排序算法对简单的整型数组进行排序,并输出排序结果。 源码&#xff1a;#include <iostre…

分享一个简单线性dp

我们可以o(n^2)&#xff0c;枚举每一个布告&#xff0c;然后从后往前枚举i前面的位置&#xff0c;然后状态转移 void solve() {int n;cin >> n;vector<int> a(n 1);for (int i 1; i < n; i) cin >> a[i];vector<int> f(n 1, 0x3f3f3f3f);f[0] …

【分隔链表】python刷题记录

R3-双指针&#xff08;快慢指针&#xff09; 新建两个链表 一个链表记录<x的值 一个链表记录>x的值 拼接即可 # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next ne…

C语言 | Leetcode C语言题解之第322题零钱兑换

题目&#xff1a; 题解&#xff1a; int coinChange(int* coins, int coinsSize, int amount) {int dp[coinsSize1][amount1];for(int i0;i<coinsSize;i){for(int j0;j<amount;j){dp[i][j]INT_MAX-1;//初始化值为INT_MAX-1&#xff0c;避免后续加一导致溢出}}for(int i0;…

Python | Leetcode Python题解之第321题拼接最大数

题目&#xff1a; 题解&#xff1a; class Solution:def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:m, n len(nums1), len(nums2)maxSubsequence [0] * kstart, end max(0, k - n), min(k, m)for i in range(start, end 1):subsequen…

语言无界,沟通无限:2024年好用在线翻译工具推荐

随着技术的发展现在的翻译在线工具从基础词句翻译到复杂的文章翻译都不在话下。为了防止你被五花八门的工具挑花眼&#xff0c;我给你介绍几款我用过的便捷、高效、准确的翻译工具吧。 1.福晰翻译端 链接直通&#xff1a;https://www.foxitsoftware.cn/fanyi/ 这个软件支持…

Google上架:8月份政策改动,未在8月31日前回应做出改动的包体将会有下架的风险

谷歌一直以用户为中心的服务思想,政策一直在变动,未及时变动的包体又下架甚至封号的风险,如有以下情况,请及时检查包体或账号相关问题,希望能给各位开发者带来帮助。 截止提交时间 2024-08-31 支付相关要求变动公布日期改动须知更改要求垃圾应用包体与用户体验公布日期改动…

LinuxC++(9):进程

linux信号 linux信号单指给进程发送的信息。比如killall 就是杀死进程&#xff0c;其实这个描述并不准确&#xff0c;应该是给程序发送一个信号&#xff0c;让程序自我了断&#xff0c;并不是我们亲自动手。 为什么直接杀死进程不好&#xff1f; 因为直接杀死进程&#xff0…

JAVA毕业设计|ssm基于ssm的宠物医院管理系统的设计与实现vue包含文档代码讲解

收藏点赞不迷路 关注作者有好处 文末获取源码 一、系统展示 二、万字文档展示 基于ssm基于ssm的宠物医院管理系统的设计与实现vue 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringSpringMVCMyBatisVue 工具&#xff1a;IDEA/Ecilpse、Navicat、Ma…

SQL注入实例(sqli-labs/less-5)

0、初始页面 1、确定闭合字符 ?id1 and 11 ?id1 and 12 ?id1 ?id1 -- 在进行前两句传参时&#xff0c;页面没有发生任何变化&#xff0c;但是当使用单引号闭合时&#xff0c;报错了。通过报错可以确定闭合符号为单引号。 2、爆库名 ?id1 and updatexml(1,concat(0x7e,(…

腾讯HunyuanDit代码解析

注意&#xff1a;本文仅供自己记录学习过程使用。 训练 全参训练过程 输入图像用VAE编码得到输入的x_start(1,4,128,128)&#xff1b;文本的两个特征&#xff1a;bert的encoder feature(1,77,1024)和T5 的feature(1,256,2048)&#xff0c;和旋转位置编码freqs_cis_img: cos …

4.8.双向循环神经网络

双向循环神经网络 ​ 在序列模型中&#xff0c;我们总是关注之前的信息&#xff0c;并以此来对下一个输出进行预测&#xff0c;但可能未来的信息也很重要&#xff0c;比如文本序列填空&#xff1a; 我___。我___饿了。我___饿了&#xff0c;我可以吃半头猪。 ​ 我们可以分别…

数据安全复合治理与实践

数据安全复合治理与实践 关键要点理论与实践 本文探讨了数据安全复合治理模式的理论与实践&#xff0c;着重强调了在数字经济迅猛发展的背景下&#xff0c;数据安全的重要性以及面对数据安全挑战时所需采取的综合治理策略。首先&#xff0c;文章概述了数据安全治理的必要性&…

使用GPT-4o mini融合GraphRAG技术进行实战应用

什么是gpt-4o mini OpenAI 推出 GPT-4o mini&#xff0c;这是他们最具成本效益的小型模型。它的定价为每百万输入代币 15 美分&#xff0c;每百万输出代币 60 美分&#xff0c;比之前的 Frontier 型号便宜一个数量级&#xff0c;比 GPT-3.5 Turbo 便宜 60% 以上。目前&#xf…

Java 并发编程:一文了解 synchronized 的使用

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 027 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

练题模块环境搭建

文章目录 1.数据库表设计1.practice_set 套卷2.practice_set_detail 套卷细节3.practice_info 练习信息4.practice_detail 练习详情5.E-R图 2.架构设计&#xff08;三层架构&#xff09;3.练题微服务架构搭建1.创建一个练题微服务模块1.创建一个maven项目2.把src删除&#xff0…

类中特殊变量的初始化

在C的类中有一些变量的初始化需要进行特殊化的处理&#xff0c;这里我将列举出常见的两种特殊类型的变量初始化。 目录 const 类型数据的初始化 代码实例&#xff1a; static类型数据的初始化 代码实例&#xff1a; const 类型数据的初始化 对于const修饰的数据我们需要在…