Spring容器启动流程——refresh()单个方法分析
文章目录
- Spring启动过程
- this()方法
- refresh()
- prepareRefresh()
- obtainFreshBeanFactory()
- prepareBeanFactory()
- postProcessBeanFactory()
- invokeBeanFactoryPostProcessors
- registerBeanPostProcessors
- initMessageSource()
- initApplicationEventMulticaster()
- onRefresh()
- registerListeners()
- finishBeanFactoryInitialization
- finishRefresh()
Spring启动过程
Spring启动过程 在线流程图
运行下面代码启动Spring的时候,会经过下面的一些步骤:
创建一个BeanFactory --> 解析指定的配置类 —> 进行包扫描 —> 生成BeanDefinition --> BeanDefinitionMap、BeanpostProcessor、单例池
public static void main(String[] args) {// 创建一个Spring容器AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) context.getBean("userService");userService.test();
}
创建一个DefaultListableBeanFactory,在创建AnnotationConfigApplicationContext这个类时,会先初始化它的父类,在父类的构造函数中会创建一个DefaultListableBeanFactory
对象,并赋值给BeanFactory属性
// GenericApplicationContext就是AnnotationConfigApplicationContext的父类
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {private final DefaultListableBeanFactory beanFactory;....../*** beanDefinitionMap、beanDefinitionNames等等常见的集合都是在DefaultListableBeanFactory这个类中的* Create a new GenericApplicationContext.*/public GenericApplicationContext() {this.beanFactory = new DefaultListableBeanFactory();}......
}
this()方法
这里主要就是给BeanFactory设置一些内容
接下来回到创建AnnotationConfigApplicationContext类的构造方法中
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScannerthis();// 通过上一步创建的reader,把将参数传递过来的componentClasses生成BeanDefinition,并存入BeanDefinitionMap中register(componentClasses);refresh();
}// 上面this()方法会到这里来
public AnnotationConfigApplicationContext() {StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");// 重点就是会创建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScannerthis.reader = new AnnotatedBeanDefinitionReader(this);createAnnotatedBeanDefReader.end();this.scanner = new ClassPathBeanDefinitionScanner(this);}
在创建AnnotatedBeanDefinitionReader
类的构造方法中,最终会调用到AnnotationConfigUtils.registerAnnotationConfigProcessors()
方法中,在该方法中就会往BeanFactory中注册很多常见的BeanPostProcessor。比如判断一个类能不能进行依赖注入、专门解析配置类的、@Autowired和@Resource注解相关的、事件相关的
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {// 设置beanFactory的OrderComparator为AnnotationAwareOrderComparator// 它是一个Comparator,是一个比较器,可以用来进行排序,比如new ArrayList<>().sort(Comparator);if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}// 用来判断某个Bean能不能用来进行依赖注入if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);// 注册ConfigurationClassPostProcessor类型的BeanDefinition// 它就是用来解析配置类的if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册AutowiredAnnotationBeanPostProcessor类型的BeanDefinitionif (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册CommonAnnotationBeanPostProcessor类型的BeanDefinition// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册PersistenceAnnotationBeanPostProcessor类型的BeanDefinition// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册EventListenerMethodProcessor类型的BeanDefinition,用来处理@EventListener注解的if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}// 注册DefaultEventListenerFactory类型的BeanDefinition,用来处理@EventListener注解的if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;
}
接下来是创建ClassPathBeanDefinitionScanner
扫描器会进行的一些操作,这里就只是对@Component注解进行扫描的功能,在ClassPathScanningCandidateComponentProvider.registerDefaultFilters()
方法中
protected void registerDefaultFilters() {// 注册@Component对应的AnnotationTypeFilterthis.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.}try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}
}
refresh()
上面只是给BeanFactory设置了一些内容,但肯定是还没有设置完的。接下来的重点就是在refresh()方法中
接下来方便写笔记,我们把AnnotationConfigApplicationContext
成为Spring容器,把AnnotationConfigWebApplicationContext
成为SPringMVC容器
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScannerthis();// 通过上一步创建的reader,把将参数传递过来的componentClasses生成BeanDefinition,并存入BeanDefinitionMap中register(componentClasses);refresh();
}
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.// 往Environment中添加一些环境变量,并检查是否有必须的环境变量// 在Spring容器中没有重写该方法,所以执行的是一个空方法,而在Springmvc容器中重写了该方法,会把ServletContext中的参数对设置到EnvironmentprepareRefresh();// Tell the subclass to refresh the internal bean factory.// 这里会判断能否刷新,并且返回一个BeanFactory, 刷新不代表完全情况,主要是先执行Bean的销毁,// 然后重新生成一个BeanFactory,再在接下来的步骤中重新去扫描等等// 我们这里使用Spring容器的父类的该方法的实现中,它不允许我们重复刷新,SpringMVC的那个类允许重复刷新,重复刷新就是调用refresh()方法// Spring容器这里其实就是把上一步构造方法中创建的BeanFactory对象直接返回ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// 准备BeanFactory// 1. 设置BeanFactory的类加载器、SpringEL表达式解析器、类型转化注册器// 2. 添加三个BeanPostProcessor,注意是具体的BeanPostProcessor实例对象// 3. 记录ignoreDependencyInterface// 4. 记录ResolvableDependency// 5. 添加三个单例BeanprepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 子类来设置一下BeanFactorypostProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.// BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理// 默认情况下:// 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition// 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor// 这里会执行ConfigurationClassPostProcessor进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中// 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行invokeBeanFactoryPostProcessors(beanFactory); // scanner.scan()// Register bean processors that intercept bean creation.// 将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.// 设置ApplicationContext的MessageSource,要么是用户设置的,要么是DelegatingMessageSourceinitMessageSource();// Initialize event multicaster for this context.// 设置ApplicationContext的applicationEventMulticaster,要么是用户设置的,要么是SimpleApplicationEventMulticasterinitApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 给子类的模板方法onRefresh();// Check for listener beans and register them.// 把定义的ApplicationListener的Bean对象,设置到ApplicationContext中去,并执行在此之前所发布的事件registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 完成Bean工厂的初始化,在这个方法内部会去实例化非懒加载的单例BeanfinishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {......}finally {......}}
}
prepareRefresh()
往Environment中添加一些环境变量,并检查是否有必须的环境变量
父类中定义的方法模板,子类去实现的重写的,AnnotationConfigApplicationContext没有重写该方法,但是SpringMVC的那个类重写了。比如子类可以把ServletContext中的参数对设置到Environment
还会对Environment进行有没有启动时必须要有的环境变量
// 创建一个Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
// Spring启动时 测试设置必须要有的环境变量
context.getEnvironment().setRequiredProperties("aaaa");context.refresh();
还有一些其他的监听器相关的
obtainFreshBeanFactory()
也是一个父类的模板方法,根据子类自己的具体实现去运行
这里会判断能否刷新,并且返回一个BeanFactory, 刷新不代表完全情况,主要是先执行Bean的销毁,然后重新生成一个BeanFactory,再在接下来的步骤中重新去扫描等等
我们这里使用Spring的AnnotationConfigApplicationContext
容器的父类的该方法的实现中,它不允许我们重复刷新,SpringMVC的AnnotationConfigWebApplicationContext
类允许重复刷新,重复刷新就是使用context重复调用refresh()方法
Spring的AnnotationConfigApplicationContext
容器这里其实就是把构造方法中创建的BeanFactory对象直接返回
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
context.refresh();
context.refresh();
context.refresh();
prepareBeanFactory()
- 把类加载器设置到BeanFactory的属性中
- 如果支持EL表达式,那么就去创建一个SpringEL表达式解析器
- 注册一些默认的类型转换器
- 添加一些BeanPostProcessor,用来处理一些Aware回调
- 添加一些Aware类型的接口到ignoredDependencyInterfaces这个Set集合中,Spring原始依赖注入时会判断忽略这个集合中的类型
- 往resolvableDependencies这个Map中添加四个对象,依赖注入在
DefaultListableBeanFactory.findAutowireCandidates()
方法根据类型找bean对象会用到这个Map - 往BeanFactory中添加ApplicationListenerDetector监听器
- Aspectj相关的代码,不用太理会
- 添加一些环境变量相关的bean进单例池中
postProcessBeanFactory()
也是一个父类的模板方法,根据子类自己的具体实现去运行
invokeBeanFactoryPostProcessors
BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理
这里会把BeanFactory当做方法参数传进去,在该方法中会去进行包扫描scanner.scan(),把扫描得到的BeanDefinition放到BeanFactory中。
在上面笔记 《Bean生命周期——生成BeanDefinition》 这一节有详细的介绍
registerBeanPostProcessors
将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去
上一个invokeBeanFactoryPostProcessors()方法会去进行包扫描,会扫描到我们自己定义的一些BeanPostProcessor,通过本方法添加进BeanFactory中去。
initMessageSource()
我们知道ApplicationContext相比较于BeanFactory而言,它是支持国际化功能的。
我们在使用国际化功能时,是会使用@Bean自己在配置类中写一个返回MessageSource的方法的。
因为之前的步骤已经包扫描完成了,这里会通过beanFactory.getBean("messageSource",MessageSource.class)
得到这个MessageSource的Bean对象,然后赋值给BeanFactory的messageSource属性。
// 如果我们自己没有定义,Spring则默认生成一个
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
initApplicationEventMulticaster()
和上一个国际化方法一样,这个是事件发布器。我们知道ApplicationContext相比较于BeanFactory而言,它是支持事件发布功能的。
我们在使用国际化功能时,是会使用@Bean自己在配置类中写一个返回ApplicationEventMulticaster的方法的。
因为之前的步骤已经包扫描完成了,这里会通过beanFactory.getBean("applicationEventMulticaster",ApplicationEventMulticaster.class)
得到这个ApplicationEventMulticaster的Bean对象,然后赋值给BeanFactory的applicationEventMulticaster属性。
// 如果我们自己没有定义,Spring则默认生成一个
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
onRefresh()
也是一个父类的模板方法,根据子类自己的具体实现去运行
registerListeners()
把程序员自己定义的ApplicationListener的Bean对象,设置到ApplicationContext中去,并执行在此之前所发布的事件
finishBeanFactoryInitialization
完成Bean工厂的初始化,在这个方法内部会去实例化非懒加载的单例Bean
在上面笔记 《Bean生命周期——Spring容器启动时创建单例Bean》 这一节有详细的介绍
finishRefresh()
Spring容器启动完成后如果我们想要运行某些代码,就是通过此方法实现的
这里会通过beanFactory.getBean("lifecycleProcessor",LifecycleProcessor.class)
得到这个LifecycleProcessor的Bean对象,然后赋值给BeanFactory的lifecycleProcessor属性。
然后在Spring容器启动完成后就会调用这个Bean对象的onRefresh()
方法,也就是最终会调用start()
方法
protected void finishRefresh() {...// 设置lifecycleProcessor,默认为DefaultLifecycleProcessorinitLifecycleProcessor();// 调用LifecycleBean的start()getLifecycleProcessor().onRefresh();...
}
@Component
public class HsLifecycle implements SmartLifecycle{@Overridepublic void start() {// Spring容器启动完成就会调用该方法System.out.println("start...");}@Overridepublic void stop() {}@Overridepublic boolean isRunning() {// 这个返回值为true才会调用stop()方法,为false则会调用start()方法return false;}
}
相关文章:

Spring容器启动流程——refresh()单个方法分析
文章目录 Spring启动过程this()方法refresh()prepareRefresh()obtainFreshBeanFactory()prepareBeanFactory()postProcessBeanFactory()invokeBeanFactoryPostProcessorsregisterBeanPostProcessorsinitMessageSource()initApplicationEventMulticaster()onRefresh()registerLi…...
Redis--注册中心集群 Cluster 集群
准备工作: 首先pull用到的镜像 docker pull redis:6.0.8 端口准备 node01 192.168.248.189.6381-6382 node02 192.168.248.190 6383-6384 node03 192.168.248.191 6385-6386 创建路径: mkdir -p /soft/docker/redis-cluster cd /soft/docker/re…...

秋招突击——6/20——复习{(单调队列优化)——最大子序列和,背包问题——宠物小精灵收服问题}——新作{两两交换链表中的节点}
文章目录 引言复习单调队列优化——最大子序列和思路分析实现代码参考实现 背包问题——宠物小精灵的收服问题个人实现参考实现 新作两两交换链表中的节点个人实现参考实现 删除有序数组中的重复项个人实现知识补全迭代器的访问和控制vector删除特定的元素erasevector底层删除元…...

使用 MongoDB 剖析开放银行:技术挑战和解决方案
开放银行(或开放金融)在银行业掀起了一股颠覆性浪潮,它迫使金融机构(银行、保险公司、金融科技公司、企业甚至政府机构)迎接一个透明、协作和创新的新时代。这种模式转变要求银行与第三方提供商(TPP&#x…...

鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段二
一、鸿蒙应用界面开发 弹性布局-Flex 语法 /* 弹性容器组件 Flex() 位置: Flex默认主轴水平往右,交叉轴垂直向下(类似Row) 语法: Flex(参数对象){子组件1,子组件2,子组件3 } 属性方法: direction…...

26.4 Django 视图层
1. 视图函数 视图函数是Django框架中用于处理Web请求并返回Web响应的重要组件. 以下是对Django视图函数的详细解释: * 1. 视图函数与URL的映射.为了让Django能够知道哪个URL对应哪个视图函数, 需要在应用的urls.py文件中定义URL模式.使用path或re_path函数来定义URL模式, 并将…...
Hbase介绍
Hbase介绍 HBase 是一个开源的、分布式的、面向列的 NoSQL 数据库系统,它建立在 Apache Hadoop 之上,提供了高可靠性、高性能、可伸缩性和高可用性的存储解决方案。让我来简单介绍一下 HBase 的架构。 1. 架构概述: HBase 的架构设计基于 Go…...

rollup学习笔记
一直使用的webpack,最近突然想了解下rollup,就花点时间学习下. 一,什么是rollup? rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,比如我们的es6模块化代码,它就可以进行tree shaking,将无用代码进行清除,打包出精简可运行的代码包. 业…...

多商户零售外卖超市外卖商品系统源码
构建你的数字化零售王国 一、引言:数字化零售的崛起 在数字化浪潮的推动下,零售业务正经历着前所未有的变革。多商户零售外卖超市商品系统源码应运而生,为商户们提供了一个全新的数字化零售解决方案。通过该系统源码,商户们可以…...
HTML 教程
HTML 教程 HTML(HyperText Markup Language)是一种用于创建网页的标准标记语言。它描述了一个网站的结构骨架,使得浏览器能够展示具有特定格式的文本、链接、图片和其他内容。本教程将带你深入了解HTML的基础知识,包括其语法、常用标签以及如何构建一个基本的网页结构。 …...
【仿真建模-解析几何】求有向线段上距指定点最近的坐标
Author:赵志乾 Date:2024-06-25 Declaration:All Right Reserved!!! 问题描述: 有向线段起点A为(x1,y1),终点B为(x2,y2&a…...
Linux系统中常用的基本命令
1. 文件与目录管理 ls: 列出目录内容。cd: 切换当前工作目录。pwd: 显示当前工作目录的路径。mkdir: 创建一个新目录。rmdir: 删除空目录。cp: 复制文件或目录。mv: 移动或重命名文件或目录。rm: 删除文件或目录。touch: 创建一个空文件或更新文件时间戳。 2. 文本内容查看 …...

数据结构与算法:回溯算法约束条件:剪枝详解、示例(C#、C++)与回溯典型例题详解
文章目录 一、约束条件二、剪枝三、典型例题四、常用术语五、示例N 皇后问题 C# 示例N 皇后问题 C 示例 六、常见用用回溯算法解决的问题汇总组合问题:图论问题:棋盘游戏问题:优化问题:调度问题:其他问题: …...
利用sortablejs实现拖拽排序
import Sortable from "sortablejs";created() {//禁止火狐拖拽进行搜索document.body.ondrop function(event){event.preventDefault();event.stopPropagation();}}// 打开对话框的时候调用下openCustomDialog(){this.rowDrop()}// 行拖拽 rowDrop() {this.$nextTi…...

超越AnimateAnyone, 华中科大中科大阿里提出Unimate,可以根据单张图片和姿势指导生成视频。
阿里新发布的UniAnimate,与 AnimateAnyone 非常相似,它可以根据单张图片和姿势指导生成视频。项目核心技术是统一视频扩散模型,通过将参考图像和估计视频内容嵌入到共享特征空间,实现外观和动作的同步。 相关链接 项目࿱…...

【MDK5问题】:MDK5无法跳转,并且提示:no browse information available in xxxxx
1、问题: MDK5原来的函数调用可以直接跳转到原函数,但是出现不能跳转原函数的情况,且提示:no browse information available in xxxxx 的情况; 2、解决: 如下图所示:在魔术棒(pro…...

OS中断机制-外部中断触发
中断函数都定义在中断向量表中,外部中断通过中断跳转指令触发中断向量表中的中断服务函数,中断指令可以理解为由某个中断寄存器的状态切换触发的汇编指令,这个汇编指令就是中断跳转指令外部中断通过在初始化的时候使能对应的中断服务函数如何判断外部中断被触发的条件根据Da…...
LabVIEW如何进行电磁兼容性测试
电磁兼容性(EMC)测试是确保电子设备在其工作环境中能够正常运行且不会对其他设备产生有害干扰的关键步骤。LabVIEW作为一种强大的系统设计和开发工具,可以有效地用于电磁兼容性测试。以下是如何使用LabVIEW进行电磁兼容性测试的详细步骤和方法…...
Spring底层架构核心概念总结
Spring底层架构核心概念总结 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! Spring框架是Java企业级应用开发中最受欢迎的框架之一。它以其强大的依赖注入&am…...

hex、bin、elf、s19等文件格式介绍以及格式转换
文章目录 前言一、bin文件二、hex文件数据记录格式扩展线性地址记录(HEX386)格式扩展段地址记录(HEX86)文件结束(EOF)记录三、elf文件四、S19文件五、不同格式之间转换将bin文件转换成hex文件将hex文件转换成bin文件将bin文件转换成s19文件前言 编译器或汇编器将程序的源代码(…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...