SpringBoot源码解析(十一):准备应用上下文
SpringBoot源码系列文章
SpringBoot源码解析(一):SpringApplication构造方法
SpringBoot源码解析(二):引导上下文DefaultBootstrapContext
SpringBoot源码解析(三):启动开始阶段
SpringBoot源码解析(四):解析应用参数args
SpringBoot源码解析(五):准备应用环境
SpringBoot源码解析(六):打印Banner
SpringBoot源码解析(七):应用上下文结构体系
SpringBoot源码解析(八):Bean工厂接口体系
SpringBoot源码解析(九):Bean定义接口体系
SpringBoot源码解析(十):应用上下文AnnotationConfigServletWebServerApplicationContext构造方法
SpringBoot源码解析(十一):准备应用上下文
目录
- 前言
- 源码入口
- 一、执行应用上下文初始化器
- 1、获取上下文初始化器
- 2、执行初始化器
- 2.1、DelegatingApplicationContextInitializer
- 2.2、SharedMetadataReaderFactoryContextInitializer
- 2.3、ContextIdApplicationContextInitializer
- 2.4、ConfigurationWarningsApplicationContextInitializer
- 2.5、RSocketPortInfoApplicationContextInitializer
- 2.6、ServerPortInfoApplicationContextInitializer
- 2.7、ConditionEvaluationReportLoggingListener
- 二、触发应用监听器(上下文准备完成)
- 三、关闭引导上下文
- 四、触发应用监听器(上下文加载完成)
- 总结
前言
在前文中,我们介绍了应用上下文的构造方法初始化两个组件:注解Bean定义读取器和类路径Bean定义扫描器,接下来,我们将探究下准备应用上下文阶段对外的扩展点。
SpringBoot版本2.7.18SpringApplication的run方法的执行逻辑如下,本文将详细介绍第8小节:刷新上下文
// SpringApplication类方法
public ConfigurableApplicationContext run(String... args) {// 记录应用启动的开始时间long startTime = System.nanoTime();// 1.创建引导上下文,用于管理应用启动时的依赖和资源DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 配置无头模式属性,以支持在无图形环境下运行// 将系统属性 java.awt.headless 设置为 trueconfigureHeadlessProperty();// 2.获取Spring应用启动监听器,用于在应用启动的各个阶段执行自定义逻辑SpringApplicationRunListeners listeners = getRunListeners(args);// 启动开始方法(发布开始事件、通知应用监听器ApplicationListener)listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 3.解析应用参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 4.准备应用环境,包括读取配置文件和设置环境变量ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 配置是否忽略 BeanInfo,以加快启动速度configureIgnoreBeanInfo(environment);// 5.打印启动BannerBanner printedBanner = printBanner(environment);// 6.创建应用程序上下文context = createApplicationContext();// 设置应用启动的上下文,用于监控和管理启动过程context.setApplicationStartup(this.applicationStartup);// 7.准备应用上下文,包括加载配置、添加 Bean 等prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 8.刷新上下文,完成 Bean 的加载和依赖注入refreshContext(context);// 9.刷新后的一些操作,如事件发布等afterRefresh(context, applicationArguments);// 计算启动应用程序的时间,并记录日志Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 10.通知监听器应用启动完成listeners.started(context, timeTakenToStartup);// 11.调用应用程序中的 `CommandLineRunner` 或 `ApplicationRunner`,以便执行自定义的启动逻辑callRunners(context, applicationArguments);}catch (Throwable ex) {// 12.处理启动过程中发生的异常,并通知监听器handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 13.计算应用启动完成至准备就绪的时间,并通知监听器Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {// 处理准备就绪过程中发生的异常handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}// 返回已启动并准备就绪的应用上下文return context;
}
源码入口
// 7.准备应用上下文,包括加载配置、添加 Bean 等
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
/*** 预处理应用上下文,在应用上下文刷新之前执行一系列准备工作。* * @param bootstrapContext 引导上下文,存储启动过程中的关键组件* @param context Spring 应用上下文 AnnotationConfigServletWebServerApplicationContext * @param environment Spring 运行环境* @param listeners Spring 应用运行监听器* @param applicationArguments 应用程序运行参数* @param printedBanner 启动时显示的 Banner*/
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 设置应用环境context.setEnvironment(environment);// 对ApplicationContext进行处理(没啥重要内容,略过)postProcessApplicationContext(context);// 1. 执行应用程序上下文的初始化器applyInitializers(context);// 2. 触发 contextPrepared 事件,通知监听器上下文已准备好listeners.contextPrepared(context);// 3. 关闭引导上下文,因为之后不再需要bootstrapContext.close(context);// 记录应用启动信息(仅在日志启用时)if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 获取 Bean 工厂,并注册特定的单例 Bean(后面章节注册Bean详解)ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 注册命令行参数(使其可被 Spring 容器访问)beanFactory.registerSingleton("springApplicationArguments", applicationArguments);// 注册启动 Banner(如果存在)if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}// 配置 Bean 工厂的属性if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {// 允许/禁止循环依赖(Spring 5 改为默认禁用循环依赖)((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);// 允许/禁止 BeanDefinition 覆盖(默认禁止)if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}}// 如果启用了懒加载,则添加Bean工厂后处理器(推迟 Bean 初始化)// 后面执行Bean工厂后置处理器时候详解if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// 添加属性源排序后处理器,确保 `@PropertySource` 注解的顺序正确// @PropertySource 注解让你能够加载外部配置文件,并将配置文件中的属性注入到 Spring 的 Environment 中context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// 加载应用的所有源(配置类、XML 文件、组件扫描等)Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty"); // 这里就是将SpringBoot配置类注册为Bean定义放到bean工厂load(context, sources.toArray(new Object[0]));// 4. 触发 contextLoaded 事件,通知监听器上下文已加载完成listeners.contextLoaded(context);
}
一、执行应用上下文初始化器
protected void applyInitializers(ConfigurableApplicationContext context) {// 遍历所有需要应用到应用上下文的初始化器for (ApplicationContextInitializer initializer : getInitializers()) {// 通过 GenericTypeResolver 解析初始化器的泛型类型参数,确定所需的上下文类型Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);// 断言当前上下文的类型是否符合要求(指定类型、子类或实现类),如果不符合则抛出异常Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");// 使用初始化器对应用上下文进行初始化initializer.initialize(context);}
}
1、获取上下文初始化器
上下文初始化器是在SpringApplication构造方法中读取spring.factories文件获取的,这里就是将上下文初始化器集合拿来根据Ordered接口或@Order排序
// SpringApplication构造方法中读取spring.factories文件获取的
private List<ApplicationContextInitializer<?>> initializers;// 获取应用上下文的初始化器集合
public Set<ApplicationContextInitializer<?>> getInitializers() {// 将初始化器集合转换为一个不可修改的、有序集合并返回return asUnmodifiableOrderedSet(this.initializers);
}// 将一个集合转换为一个不可修改的、有序的 Set
private static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) {// 将集合转换为列表,以便对其进行排序List<E> list = new ArrayList<>(elements);// 使用 AnnotationAwareOrderComparator 对列表进行排序// 通过Ordered接口或@Order排序list.sort(AnnotationAwareOrderComparator.INSTANCE);// 将排序后的列表转换为 LinkedHashSet,确保元素的顺序被保留return new LinkedHashSet<>(list);
}
debug看下获取到的初始化器

2、执行初始化器
执行初始化器调用ApplicationContextInitializer实现类的initialize方法,下面逐一分析。
2.1、DelegatingApplicationContextInitializer
简单描述一下,就是通过配置文件属性名context.initializer.classes获取到多个初始化器,然后再遍历调用每个初始化器的。

举例
假设在application.properties或通过命令行参数配置了以下内容:
context.initializer.classes=com.example.MyCustomInitializer,com.example.AnotherInitializer
Spring在启动时会解析这个属性,并按照顺序实例化并调用 MyCustomInitializer 和 AnotherInitializer 类,这些类都应该实现ApplicationContextInitializer接口,负责在应用上下文初始化时进行自定义操作。
DelegatingApplicationContextInitializer适用于需要在 Spring 应用程序启动时,按顺序动态加载和执行多个不同的应用上下文初始化器的场景,特别是在具有多个模块或复杂配置的应用中。例如,当需要根据不同的环境配置(如开发、测试、生产环境)执行不同的初始化任务,或者在应用启动时灵活地执行自定义的初始化逻辑(如数据库连接配置、安全设置或外部服务的初始化)时,使用DelegatingApplicationContextInitializer可以帮助通过配置文件集中管理多个初始化器,确保它们按照指定的顺序正确执行。
2.2、SharedMetadataReaderFactoryContextInitializer
SharedMetadataReaderFactoryContextInitializer 是 Spring 框架中的一个初始化器,它在 Spring 应用上下文初始化过程中,负责确保 MetadataReaderFactory 实例在整个上下文中共享,避免每次进行类路径扫描时都重新创建该工厂实例。MetadataReaderFactory主要用于读取和解析类的元数据,尤其是在注解扫描过程中,例如扫描 @Component, @Service, @Repository 等注解。通过共享MetadataReaderFactory,SharedMetadataReaderFactoryContextInitializer提高了类路径扫描的效率,减少了内存消耗和性能开销,尤其在大型或复杂的 Spring 应用中,能够加速启动过程。
2.3、ContextIdApplicationContextInitializer
ContextIdApplicationContextInitializer 是 Spring 框架中的一个初始化器类,主要用于为 Spring 应用上下文生成一个唯一的 ID,并将其设置到应用上下文的环境中。这个 ID 通常用于标识不同的应用上下文实例,尤其在有多个 Spring 应用上下文存在的情况下,可以帮助区分它们。
2.4、ConfigurationWarningsApplicationContextInitializer
ConfigurationWarningsApplicationContextInitializer 是 Spring 框架中的一个应用上下文初始化器,它用于在 Spring 应用程序启动时检查并发出有关配置方面的警告,尤其是关于弃用的配置或潜在不推荐的配置。它的主要作用是在应用上下文初始化期间,帮助开发者识别不再推荐使用的配置或可能导致问题的配置方式。
2.5、RSocketPortInfoApplicationContextInitializer
RSocketPortInfoApplicationContextInitializer 是一个 Spring 应用上下文初始化器,专门用于确保RSocket协议相关的端口信息在 Spring 应用启动时得到正确配置和初始化,特别适用于使用 RSocket 协议进行高效、双向通信的应用场景,如微服务架构和实时通信应用。
2.6、ServerPortInfoApplicationContextInitializer
ServerPortInfoApplicationContextInitializer是一个确保在 Spring 启动时正确加载、处理和应用服务器端口信息的初始化器,它在处理动态端口配置、跨环境配置或微服务架构中的端口共享方面尤其有用。
2.7、ConditionEvaluationReportLoggingListener
ConditionEvaluationReportLoggingListener 是 Spring Framework 中的一个类,用于在应用启动过程中记录和输出条件注解(如 @Conditional)的评估报告。它会将 Spring 配置类中的条件评估结果打印到日志中,帮助开发者了解哪些条件被满足,哪些未被满足,以及哪些 Bean 被加载或跳过
举例
如果在启动应用时使用 @Conditional 注解条件来控制 Bean 的加载,ConditionEvaluationReportLoggingListener 会在日志中输出类似如下的信息:
2018-12-04 16:42:52.755 INFO 12345 --- [ main] o.s.boot.autoconfigure.ConditionEvaluationReportLoggingListener :
Evaluating conditions on com.example.SomeConfiguration- @ConditionalOnProperty (spring.datasource.url) matched => Spring DataSource Bean created- @ConditionalOnMissingBean (org.springframework.jdbc.datasource.DataSource) matched => Spring DataSource Bean created
二、触发应用监听器(上下文准备完成)
listeners内部持有多个SpringApplicationRunListener(用于监听Spring应用程序启动过程的生命周期事件),这里在上下文准备完成时遍历所有SpringApplicationRunListener触发contextPrepared方法。
// 2. 触发 contextPrepared 事件,通知监听器上下文已准备好
listeners.contextPrepared(context);

唯一的Spring应用启动监听器EventPublishingRunListener的上下文准备完成方法核心内容就是广播应用上下文初始化事件,将其推给合适的监听器(匹配监听器的事件类型,这里就是匹配上下文初始化事件的监听器)

虽然匹配到了如下应用监听器,但无操作内容
三、关闭引导上下文
// 3. 关闭引导上下文,因为之后不再需要
bootstrapContext.close(context);
主要内容就是发布事件给合适的监听器。目前没有此事件的监听器,故无任何操作。
// DefaultBootstrapContext类方法
public void close(ConfigurableApplicationContext applicationContext) {// 发布 BootstrapContextClosedEvent 事件,通知系统上下文已关闭this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
}
BootstrapContextClosedEvent的发布和监听机制主要用于在应用程序上下文关闭时进行清理和通知。它适用于需要在应用关闭时执行清理操作、通知其他模块或外部系统、管理资源释放的场景。
四、触发应用监听器(上下文加载完成)
// 4. 触发 contextLoaded 事件,通知监听器上下文已加载完成
listeners.contextLoaded(context);
核心内容与上下文准备完成触发的监听器原理一致,就是广播特定的事件到合适的监听器,这都是spring对外的扩展点,创建对应的事件监听器,就会在对应的时机触发执行。

如下匹配到的应用监听器,也没啥重要内容,略过

总结
本文概述了SpringBoot启动过程的准备应用上下文阶段,触发上下文初始化器ApplicationContextInitializer、上下文准备完成ApplicationContextInitializedEvent事件监听器、引导上下文关闭BootstrapContextClosedEvent事件监听器、上下文加载完成ApplicationPreparedEvent事件监听器执行时机和流程,这些均可作为对外扩展点。
相关文章:
SpringBoot源码解析(十一):准备应用上下文
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...
CSS 使用white-space属性换行
一、white-space属性的常见值 * 原本格式: 1、white-space:normal 默认值,空格和换行符会被忽略过滤掉;宽度不够时文本会自动换行 * 宽度足够时,normal 处理后的格式 * 宽度不够时, normal 处理后的格式 2、white-spa…...
论文笔记(七十二)Reward Centering(四)
Reward Centering(四) 文章概括摘要附录A 伪代码 文章概括 引用: article{naik2024reward,title{Reward Centering},author{Naik, Abhishek and Wan, Yi and Tomar, Manan and Sutton, Richard S},journal{arXiv preprint arXiv:2405.09999…...
Matlab——图像保存导出成好看的.pdf格式文件
点击图像的右上角,点击第一个保存按钮键。...
官方文档学习TArray容器
一.TArray中的元素相等 1.重载一下 元素中的 运算符,有时需要重载排序。接下来,我们将id 作为判断结构体的标识。 定义结构体 USTRUCT() struct FXGEqualStructInfo {GENERATED_USTRUCT_BODY() public:FXGEqualStructInfo(){};FXGEqualStructInfo(in…...
unxi-进程间通信
1.进程间通信实现方式 【1】同一主机 linux下通信方式: a.传统的进程间通信方式 管道 --- 进行数据传输的"管道" 无名管道 有名管道 信号 --- b.system v 进程间通信 (posix 进程间通信) 共享内存 (进程间…...
微型分组加密算法TEA、XTEA、XXTEA
微型分组加密算法TEA、XTEA、XXTEA TEA(Tiny Encryption Algorithm)算法是一种分组加密算法,由剑桥大学计算机实验室的David Wheeler和Roger Needham于1994年发明。TEA、XTEA、XXTEA算法采用64位的明文分组和128位的密钥。它使用Feistel…...
conda 基本命令
1、查询当前所有的环境 conda env list 2、创建虚拟环境 conda create -n 环境名 [pythonpython版本号] 其中[pythonpython版本号]可以不写 conda create -n test python3.12 我们输入conda env list看到我们的环境创建成功了,但是发现他是创建在我们默认的C盘的…...
详解 为什么 tcp 会出现 粘包 拆包 问题
TCP 会出现 粘包 和 拆包 问题,主要是因为 TCP 是 面向字节流 的协议,它不关心应用层发送的数据是否有边界,也不会自动分割或合并数据包。由于 TCP 的流控制和传输机制,数据可能在传输过程中被拆分成多个小的 TCP 包,或…...
Linus的基本命令
以下是一些常见的 Linux 命令: 一、文件和目录操作: - ls:列出目录中的文件和子目录,常用参数有 -a (显示所有文件,包括隐藏文件)、 -l (显示详细信息)、 -h ࿰…...
【Linux】缓冲区和文件系统
个人主页~ 缓冲区和文件系统 一、FILE结构1、fd2、缓冲区(一)有换行有return全部打印(二)无换行无return的C接口打印(三)无换行无return的系统调用接口打印(四)有换行无return的C接口…...
函数式编程:概念、特性与应用
1. 函数式编程简介 函数式编程,从名称上看就与函数紧密相关。它是一种我们常常使用却可能并未意识到的编程范式,关注代码的结构组织,强调一个纯粹但在实际中有些理想化的不可变世界,涉及数学、方程和副作用等概念,甚至…...
git中的merge和rebase的区别
在 Git 中,git merge 和 git rebase 都是用于整合分支变更的核心命令,但它们的实现方式和结果有本质区别。以下是两者的详细对比: 一、核心区别 特性git mergegit rebase历史记录保留分支拓扑,生成新的合并提交线性化历史&#x…...
【目标检测】目标检测中的数据增强终极指南:从原理到实战,用Python解锁模型性能提升密码(附YOLOv5实战代码)
🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…...
uniapp在app下使用mqtt协议!!!支持vue3
什么?打包空白?分享一下我的解决方法! 第一步 找大师算过了,装4.1版本运气好! 所以根目录执行命令… npm install mqtt4.1.0第二步 自己封装一个mqtt文件方便后期开坛做法! // utils/mqtt.js import mqt…...
VMware虚拟机17.5.2版本下载与安装(详细图文教程包含安装包)
文章目录 前言一、vmware虚拟机下载二、vmware虚拟机安装教程三、vmware虚拟机许可证 前言 VMware Workstation Pro 17 功能强大,广受青睐。本教程将带你一步步完成它的安装,简单易上手,助你快速搭建使用环境。 一、vmware虚拟机下载 VMwar…...
如何加固织梦CMS安全,防webshell、防篡改、防劫持,提升DedeCMS漏洞防护能力
织梦系统(DedeCMS)是一款非常知名的CMS系统,因其功能强大、结构科学合理,深受广大用户喜欢。 虽然织梦CMS(DedeCMS)非常优秀,但是为了保障网站安全,我们还是需要做一些必要的防护措…...
STM32的HAL库开发---ADC采集内部温度传感器
一、STM32内部温度传感器简介 二、温度计算方法 F1系列: 从数据手册中可以找到V25和Avg_Slope F4、F7、H7系列只是标准值不同,自行查阅手册 三、实验简要 1、功能描述 通过ADC1通道16采集芯片内部温度传感器的电压,将电压值换算成温度后&…...
Linux 命令大全完整版(12)
Linux 命令大全 5. 文件管理命令 ln(link) 功能说明:连接文件或目录。语 法:ln [-bdfinsv][-S <字尾备份字符串>][-V <备份方式>][--help][--version][源文件或目录][目标文件或目录] 或 ln [-bdfinsv][-S <字尾备份字符串>][-V…...
Python - 代码片段分享 - Excel 数据实时写入方法
文章目录 前言注意事项工具 pandas1. 简介2. 安装方式3. 简单介绍几个api 实战片段 - 实时写入Excel文件结束语 要么出众,要么出局 前言 我们在爬虫采集过程中,总是将数据解析抓取后统一写入Excel表格文件,如果在解析数据出现问题容易出现数据…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
