SpringSecurity6 | 自动配置(下)

在这里插入图片描述
✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉
🍎个人主页:Leo的博客
💞当前专栏: Java从入门到精通
✨特色专栏: MySQL学习
🥭本文内容:SpringSecurity6 | 自动配置(下)
🖥️个人小站 :个人博客,欢迎大家访问
📚个人知识库: Leo知识库,欢迎大家访问

✨✨ 粉丝福利订阅✨✨

在这里插入图片描述
Leo哥收集了一些关于面试以及其他学习资源,这里分享给大家,各位卷王快收下吧!!!

目录

    • 1.前言
    • 2.问题引出
    • 3.再看自动装配
      • 3.1run方法到注解解读器
      • 3.2加载Bean
    • 6.参考文献
    • 7.总结

学习参考 :

  • 讲师:孙帅老师
  • 课程:孙哥说SpringSecurity6

image-20231030235443828

1.前言

大家好,我是Leo哥🫣🫣🫣,上一节我们揭开了为什么引入依赖之后就会进行登录鉴权这一神秘面纱,了解复习了关于SpringBoot的自动配置以及如何一步一步的通过自动配置让我们请求加上认证权限。本次我们接着讨论关于自动配置相关问题。好了,话不多说让我们开始吧😎😎😎。

2.问题引出

既然我们知道了有关SpringBoot自动装配的一些基本流程。具体的方法调用路径或者叫配置路径是这样的:首先是三个核心的注解:

@SpringBootApplication-> @EnableAutoConfiguration>@Import(AutoConfigurationImportSelector)

然后通过@Import注解去加载他的所有配置文件到SpringBoot中。这样加载到SpringSecurity的核心文件。最终调用到上边的方法,导致所有的方法都得进行登录认证。

那么这些个注解尤其是**@Import**是如何生效的呢,具体是怎么生效的呢,在什么时候被加载呢,其实上一篇文章我们已经有了一些简单的了解,这节课我们随着Leo哥的视角通过源码方式来深入学习一下。

3.再看自动装配

3.1run方法到注解解读器

我们找到我们项目的启动类。

image-20231117232122451

然后通过Ctrl + 鼠标左键,点进去run方法。

image-20231117232424261

我们查看这个里面的构造方法:

image-20231118123722315

然后我们找到run()方法

image-20231118124312944

image-20231118124041959

可以看到这个prepareContext这个方法。它接受6个参数,分别是bootstrapContextcontextenvironmentlistenersapplicationArguments和printedBanner,并对这些参数进行处理以准备上下文。

然后我们通过Ctrl + 鼠标左键,点到prepareContext这个里面去查看。

image-20231118124238053

那么他在这里做了什么准备工作呢,我们来简单分析一下:

它的功能是在Spring应用启动过程中准备并设置应用上下文(ApplicationContext)

  1. 设置环境并处理应用上下文:
    • context.setEnvironment(environment): 将配置环境设置到应用上下文中。
    • postProcessApplicationContext(context): 对应用上下文进行后处理,可能涉及一些自定义配置或修改。
    • addAotGeneratedInitializerIfNecessary(this.initializers): 如果需要,添加Ahead-of-Time (AOT) 生成的初始化器到应用的初始化器列表中。
    • applyInitializers(context): 应用之前添加的所有初始化器到应用上下文。
  2. 通知监听器上下文已准备好:
    • listeners.contextPrepared(context): 通知Spring应用运行监听器,上下文已准备完成。
    • bootstrapContext.close(context): 关闭引导上下文。
  3. 启动信息日志:
    • 如果启用了启动日志(this.logStartupInfo),则记录启动信息和配置文件信息。
  4. 注册Spring Boot特定的单例Bean:
    • 向Bean工厂注册springApplicationArgumentsspringBootBanner(如果存在的话)。
  5. 处理Bean工厂配置:
    • 设置允许循环引用(setAllowCircularReferences)和允许Bean定义覆盖(setAllowBeanDefinitionOverriding),根据配置决定。
  6. 懒加载和属性源排序处理:
    • 如果启用了懒加载(this.lazyInitialization),则添加相关的BeanFactoryPostProcessor。
    • 添加一个用于属性源排序的BeanFactoryPostProcessor。
  7. 加载应用的源:
    • 如果没有使用AOT生成的工件,那么将从getAllSources()获取所有源,并使用load(context, sources.toArray(new Object[0]))加载它们。
  8. 通知监听器上下文已加载:
    • listeners.contextLoaded(context): 通知监听器上下文加载完成。

主要作用: 识别入口类,读取入口类的所有内容包括注解在内。并注册到注解解读器announationreader中,方便后续注解进行解析。

通过getAllSources()获取所有源信息,也就是我们当前的入口类信息,然后把这些source放到一个set集合中,最后去加载load,接下来我们点开load方法继续查看。

image-20231118125037298

  1. 首先,它检查logger是否处于调试模式(debugEnabled)。如果处于调试模式,它会记录一条调试日志,显示正在加载的源(sources)。
  2. 然后,它创建一个BeanDefinitionLoader实例。这个实例是用于加载Bean定义的。它使用getBeanDefinitionRegistry(context)方法获取BeanDefinitionRegistry,然后使用createBeanDefinitionLoader()方法创建一个BeanDefinitionLoader实例。
  3. 如果beanNameGenerator属性不为null,它将beanNameGenerator设置为loader的属性。
  4. 如果resourceLoader属性不为null,它将resourceLoader设置为loader的属性。
  5. 如果environment属性不为null,它将environment设置为loader的属性。
  6. 最后,调用loader的load()方法来加载Bean定义。

到这里,前面的工作已经基本完成了:读取入口类中重要的信息,包括注解包括入口类本身。将入口类中的注解注册到注解解读器annotationreader当中。

3.2加载Bean

真正解析Bean的工作是从refreshContext当中进行的。

image-20231118125314882

首先通通过prepareContext方法进行准备,然后通过refreshContext进行装载工作,那么他具体是怎么进行转载的呢,下面我们点进去这个方法继续查看。

image-20231118125430218

这部分代码涉及应用上下文的刷新动作。这里我逐行解释一下:

注册关闭钩子(shutdown hook):

  • if (this.registerShutdownHook): 首先检查一个布尔标志this.registerShutdownHook,判断是否需要注册一个shutdown hook。这个标志通常是在Spring Boot的配置中设置的,用以确定我们是否希望在JVM关闭时能够自动清理和关闭Spring上下文。
  • shutdownHook.registerApplicationContext(context): 如果需要注册shutdown hook,这行代码执行注册操作。具体来说,shutdownHook是一个管理器(可能是Spring Boot中的一个组件),负责注册和执行关闭Spring应用上下文的逻辑。当JVM进程结束时,这个shutdown hook将得到执行。

最后跑到了一个applicationContext的refresh方法当中。

image-20231118125721796

刷新应用上下文:

refresh(context)

这是调用ApplicationContext的

refresh()

方法,该方法是启动和重新启动Spring上下文的核心方法。它会执行以下关键步骤:

  • 准备上下文环境(比如设置必要的属性源、验证必要的环境变量等)。
  • 实例化和初始化所有的Bean,包括Spring配置中声明的Bean以及注解声明的Bean。
  • 如果有的话,运行BeanFactory后处理器。
  • 触发任何实现ApplicationContextAware接口的Bean,让它们能够感知到自己所处的ApplicationContext。
  • 最后,发送上下文刷新事件,这将通知所有监听器上下文已经完全初始化和可用。

这个refreshContext方法的目的是确保SpringBoot应用中的ApplicationContext处于最新状态,具备服务请求的能力。这通常发生在应用启动时,或者需要重新加载上下文配置的任何时候。

接下来会进行Bean处理的13方法,其中一个比较关键的方法: invokeBeanFactoryPostProcessors

image-20231118125934988

我们点过去这个方法

image-20231118130018787

  1. invokeBeanFactoryPostProcessors 方法接收一个 ConfigurableListableBeanFactory 类型的参数 beanFactory

  2. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()) 这一行调用了 PostProcessorRegistrationDelegate 类的 invokeBeanFactoryPostProcessors 方法,传入了两个参数,即当前的 beanFactory 和获取的一些BeanFactory后处理器列表(通过 getBeanFactoryPostProcessors() 获取)。

  3. 接下来的注释提到了检测 LoadTimeWeaver 并准备进行织入(weaving)。具体地说,它通过以下条件进行检查:

    • NativeDetector.inNativeImage() 确保不在本机镜像环境下。
    • beanFactory.getTempClassLoader() == null 确保临时类加载器为空。
    • beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME) 确保BeanFactory中包含名为 LOAD_TIME_WEAVER_BEAN_NAME 的bean。
  4. 如果以上条件都满足,那么会执行以下两个操作:

    • beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)) 添加一个 LoadTimeWeaverAwareProcessor 的Bean后处理器。
    • beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())) 设置临时类加载器为 ContextTypeMatchClassLoader 类的实例,该实例使用当前的 beanFactory 的类加载器。

    总结:

    经常refresh()的层层调用2进到AbstractApplicationContext类中refresh0方法,该方法主要有13
    个步骤用于对bean对象进行解析加载,其中第5步invokeBeanFactoryPostProcessors()进行核心加
    载类上的**@Configurer**、@Bean@Import等注解。

6.参考文献

  • https://springdoc.cn/spring-security/servlet/architecture.html
  • http://springboot.fun/

7.总结

以上便是本文的全部内容,本人才疏学浅,文章有什么错误的地方,欢迎大佬们批评指正!我是Leo,一个在互联网行业的小白,立志成为更好的自己。

如果你想了解更多关于Leo,可以关注公众号-程序员Leo,后面文章会首先同步至公众号。

ToLeoJavaer公众号 (微信搜索程序员Leo)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

我叫:冒泡排序【JAVA】

1.什么是冒泡排序? 冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。 2.来个实战应用 我们…

从键盘输入5个学生的信息(姓名、学号、成绩), 存入一个结构体数组中,计算平均分,并按成绩 高低排序并输出.

代码如下 #include<stdio.h> #include<string.h> #include<stdlib.h> /* 1.练习结构体数组排序   从键盘输入5个学生的信息&#xff08;姓名、学号、成绩&#xff09;,存入一个结构体数组中&#xff0c;计算平均分&#xff0c;并按成绩高低排序并输出. */…

python学习:break用法详解

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 在执行while循环或者for循环时&#xff0c;只要循环条件满足&#xff0c;程序会一直执行循环体。 但在某些场景&#xff0c;我们希望在循环结束前就强制结束循环。 Python中有两种强制结束循环的方法&#xff1a; continue语…

heatmap | cell cycle genes in Seurat

目的&#xff1a;使用bulk 数据&#xff0c;查看HeLa 双胸苷阻断法 细胞同步化 释放 [0, 3, 4.5, 6, 9, 10.5, 12, 15, 18, 19.5, 21, 22.5, 25.5, 30] 小时后 cell cycle 基因的表达情况。 1.结果 S phase G2M phase S G2M phase 不方便看&#xff0c;横过来看&#xff1a;…

Linux下运行Jmeter压测

一、在Linux服务器先安装SDK 1、先从官网下载jdk1.8.0_131.tar.gz&#xff0c;再从本地上传到Linux服务器 2、解压&#xff1a;tar -xzf jdk1.8.0_131.tar.gz&#xff0c;生成文件夹 jdk1.8.0_131 3、在/usr/目录下创建java文件夹&#xff0c;再将 jdk1.8.0_131目录移动到/u…

【操作系统】磁盘物理地址怎么表示

常见主存物理地址是一串01串&#xff0c;那磁盘物理地址呢&#xff1f; 磁盘物理地址由以下组成&#xff1a; 柱面号磁头号扇区号 重点知识点辨析&#xff1a; 磁盘物理地址的翻译是由磁盘驱动程序进行的&#xff0c;目的是将逻辑上的蔟号转化为上述的物理地址 408真题溯源…

harmonyOS鸿蒙开发工具下载安装以及使用流程

注册账号 进入鸿蒙官方网站&#xff1a;https://www.harmonyos.com/ 推荐使用手机号注册 进行实名认证 下载开发环境 华为集成开发环境IDE DevEco Device Tool下载 | HarmonyOS设备开发 下载开发工具 HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 安装 无脑下一…

使用共享内存进行通信的代码和运行情况分析,共享内存的特点(拷贝次数,访问控制),加入命名管道进行通信的代码和运行情况分析

目录 示例代码 头文件(comm.hpp) log.hpp 基础版 -- 服务端 代码 运行情况 加入客户端 代码 运行情况 两端进行通信 客户端 代码 注意点 服务端 代码 两端运行情况 共享内存特点 拷贝次数少 管道的拷贝次数 共享内存的拷贝次数 没有访问控制 管道 共享…

Spring学习③__Bean管理

目录 IOC接口ApplicationContext 详解IOC操作Bean管理基于xml方式基于xml方式创建对象基于xml方式注入属性使用set方法进行注入通过有参数的构造进行注入p 名称空间注入&#xff08;了解&#xff09; 基于xml方式注入其他类型属性xml 注入数组类型属性 IOC接口 IOC思想基于IOC…

龙芯 操作系统选择和安装

龙芯3a5000及之后的cpu底层架构已经从mips64el改为了loongarch64 所以这里分了2种来说明&#xff0c;分别对应3a4000之前的和3a5000之后的 龙芯的系统安装难点在于操作系统的选取和引导 一、烧录工具 制作安装盘使用常规的烧录工具是不行滴&#xff0c;会提示没有\boot\initrd…

Vue 路由缓存 防止路由切换数据丢失 路由的生命周期

在切换路由的时候&#xff0c;如果写好了一丢数据在去切换路由在回到写好的数据的路由去将会丢失&#xff0c;这时可以使用路由缓存技术进行保存&#xff0c;这样两个界面来回换数据也不会丢失 在 < router-view >展示的内容都不会被销毁&#xff0c;路由来回切换数据也…

【SpringBoot3+Vue3】四【实战篇】-前端(vue基础)

目录 一、项目前置知识 二、使用vscode创建 三、vue介绍 四、局部使用vue 1、快速入门 1.1 需求 1.2 准备工作 1.3 操作 1.3.1 创建html 1.3.2 创建初始html代码 1.3.3 参照官网import vue 1.3.4 创建vue应用实例 1.3.5 准备div 1.3.6 准备用户数据 1.3.7 通过…

DPDK初始化

rte_eal_init │ ├──rte_cpu_is_supported&#xff1a;检查cpu是否支持 │ ├──rte_atomic32_test_and_set&#xff1a;操作静态局部变量run_once确保函数只执行一次 │ ├──pthread_self() 获取主线程的线程ID,只是用于打印 │ ├──eal_reset_internal_config&#x…

UE 程序化网格 计算横截面

首先在构造函数内加上程序化网格&#xff0c;然后复制网格体到程序化网格组件上&#xff0c;将Static Mesh&#xff08;类型StaticMeshActor&#xff09;的静态网格体组件给到程序化网格体上 然后把StaticMesh&#xff08;类型为StaticMeshActor&#xff09;Instance暴漏出去 …

异地工业设备集中运维、数据采集,一招搞定

为了提升运维效率&#xff0c;能够及时发现和响应设备的故障、异常和潜在问题。 越来越多的企业都在搭建“集中式”的远程智慧运维体系&#xff0c;以提高运维效率和降低成本。 异地工业设备远程运维&#xff0c;提升响应效率、降低运维成本 以国内陕西某机床公司为例&#xff…

在vmware中给linux添加硬盘

1.必须在断开linux电源的情况下&#xff0c;才能添加硬盘成功。注&#xff1a;自己好几次在开机状态下添加硬盘都失败了&#xff0c;然后关机后&#xff0c;又试了下&#xff0c;居然成功了。

Python (十一) 迭代器与生成器

迭代器 迭代器是访问集合元素的一种方式&#xff0c;可以记住遍历的位置的对象 迭代器有两个基本的方法&#xff1a;iter() 和 next() 字符串&#xff0c;列表或元组对象都可用于创建迭代器 字符串迭代 str1 Python str_iter iter(str1) print(next(str_iter)) print(next(st…

Docker入门学习笔记

学习笔记网址推送&#xff1a;wDocker 10分钟快速入门_哔哩哔哩_bilibili docker是用来解决什么问题的&#xff1f; 例如当你在本地主机写了个web应用&#xff0c;而你打算将该应用发送给其他客户端进行案例测试和运行&#xff0c;若是传统做法&#xff0c;就比较复杂&#xf…

《轻购优品》新零售玩法:消费积分认购+众筹新玩法

《轻购优品》新零售玩法&#xff1a;消费积分认购众筹新玩法 引言&#xff1a;2023年开年已来&#xff0c;政府的工作报告提出“把恢复和扩大消费摆在优先位置”&#xff0c;并且把2023年定位为“消费提振年”&#xff0c;以“全年乐享全年盛惠”为主题多地政府共同发力&#x…

mmdet 3.x 打印各类指标

和mmdet2.x中的修改地方不一样&#xff0c;在mmdet/evaluation/metrics/coco_metric.py中第72行将classwise设为True就可以打印各类指标了 但是在test的时候一直都是什么指标都不打印&#xff0c;不管是上面总的指标还是下面的各类指标&#xff0c;暂时不知道怎么处理 找到原因…