【Spring Boot 源码学习】深入应用上下文初始化器实现
《Spring Boot 源码学习系列》

深入应用上下文初始化器实现
- 一、引言
- 二、往期内容
- 三、主要内容
- 3.1 spring-boot 子模块中内置的实现类
- 3.1.1 ConfigurationWarningsApplicationContextInitializer
- 3.1.2 ContextIdApplicationContextInitializer
- 3.1.3 DelegatingApplicationContextInitializer
- 3.1.4 RSocketPortInfoApplicationContextInitializer
- 3.1.5 ServerPortInfoApplicationContextInitializer
- 3.2 spring-boot-autoconfigure 子模块中内置的实现类
- 3.2.1 SharedMetadataReaderFactoryContextInitializer
- 3.2.2 ConditionEvaluationReportLoggingListener
- 3.3 自定义应用上下文初始化器实现
- 3.3.1 定义 DemoApplicationContextInitializer
- 3.3.2 添加 DemoApplicationContextInitializer
- 3.3.3 实际演示
- 四、总结
一、引言
前面的博文《ApplicationContextInitializer 详解》,Huazie 带大家详细分析了 ApplicationContextInitializer 的加载和初始化的逻辑,不过有关 ApplicationContextInitializer 接口的实现尚未提及 。那本篇 Huazie 就带大家一起分析 Spring Boot 中预置的应用上下文初始化器实现【即 ApplicationContextInitializer 接口实现类】的源码,了解在 Spring 容器刷新之前初始化应用程序上下文的一些具体操作。

二、往期内容
在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:
| Spring Boot 源码学习 |
| Spring Boot 项目介绍 |
| Spring Boot 核心运行原理介绍 |
| 【Spring Boot 源码学习】@EnableAutoConfiguration 注解 |
| 【Spring Boot 源码学习】@SpringBootApplication 注解 |
| 【Spring Boot 源码学习】走近 AutoConfigurationImportSelector |
| 【Spring Boot 源码学习】自动装配流程源码解析(上) |
| 【Spring Boot 源码学习】自动装配流程源码解析(下) |
| 【Spring Boot 源码学习】深入 FilteringSpringBootCondition |
| 【Spring Boot 源码学习】OnClassCondition 详解 |
| 【Spring Boot 源码学习】OnBeanCondition 详解 |
| 【Spring Boot 源码学习】OnWebApplicationCondition 详解 |
| 【Spring Boot 源码学习】@Conditional 条件注解 |
| 【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解 |
| 【Spring Boot 源码学习】RedisAutoConfiguration 详解 |
| 【Spring Boot 源码学习】JedisConnectionConfiguration 详解 |
| 【Spring Boot 源码学习】初识 SpringApplication |
| 【Spring Boot 源码学习】Banner 信息打印流程 |
| 【Spring Boot 源码学习】自定义 Banner 信息打印 |
| 【Spring Boot 源码学习】BootstrapRegistryInitializer 详解 |
| 【Spring Boot 源码学习】ApplicationContextInitializer 详解 |
| 【Spring Boot 源码学习】ApplicationListener 详解 |
| 【Spring Boot 源码学习】SpringApplication 的定制化介绍 |
| 【Spring Boot 源码学习】BootstrapRegistry 详解 |
| 【Spring Boot 源码学习】深入 BootstrapContext 及其默认实现 |
| 【Spring Boot 源码学习】BootstrapRegistry 初始化器实现 |
| 【Spring Boot 源码学习】BootstrapContext的实际使用场景 |
三、主要内容
注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。
3.1 spring-boot 子模块中内置的实现类
我们先来看一张截图:

从上图中可以看出,spring-boot 子模块中配置的 ApplicationContextInitializer 实现一共有 5 个,下面我们一一来介绍下:
3.1.1 ConfigurationWarningsApplicationContextInitializer
该类用于报告常见配置错误的警告,我们来看看相关源码:
public class ConfigurationWarningsApplicationContextInitializerimplements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext context) {context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));}// 省略其他。。。
}
阅读上述源码,我们可以看到 initialize 方法里,通过 ConfigurableApplicationContext 的 addBeanFactoryPostProcessor 方法,在 应用程序上下文 中添加了一个 BeanFactoryPostProcessor 实现【 该实现类为 ConfigurationWarningsPostProcessor】。
BeanFactoryPostProcessor 是 Spring 框架中的一个接口,它的作用是在 Spring 容器初始化时对 Bean 的定义进行修改或增强【添加属性、设置依赖关系等】。
在介绍 ConfigurationWarningsPostProcessor 之前,先来看看 getChecks 方法:
protected Check[] getChecks() {return new Check[] { new ComponentScanPackageCheck() };
}
我们继续查看 ComponentScanPackageCheck ,由于篇幅受限,Huazie 贴下截图:

ComponentScanPackageCheck 是 ConfigurationWarningsApplicationContextInitializer 中的一个静态内部类,它的目的是在Spring Boot 应用启动时,检查 @ComponentScan 的使用情况,确保没有错误或不推荐的配置方式。通过 ComponentScanPackageCheck 的 getWarning 方法的检查,如果发现了不恰当的 @ComponentScan 使用,它会生成相应的警告信息,帮助开发者及时发现并修正潜在的配置问题。
下面我们可以来分析下 ConfigurationWarningsPostProcessor,如下截图:

该类也是一个静态内部类,它同时实现了 PriorityOrdered 和 BeanDefinitionRegistryPostProcessor 接口:
PriorityOrdered:实现该接口是用于提高其在多个BeanFactoryPostProcessor处理中的执行优先级。BeanDefinitionRegistryPostProcessor:它是对BeanFactoryPostProcessor的扩展,允许在常规的BeanFactoryPostProcessor检测启动之前注册更多的 bean 定义,这些定义反过来定义了BeanFactoryPostProcessor实例【可查看PostProcessorRegistrationDelegate了解】。
从上述截图中,我们可以看到 postProcessBeanFactory 方法【BeanFactoryPostProcessor 接口定义的方法】是空实现,而postProcessBeanDefinitionRegistry 方法【BeanDefinitionRegistryPostProcessor 接口定义的方法】里,遍历了 checks 数组中的每个检查项,并调用 check.getWarning(registry) 方法获取警告信息。如果警告信息不为空,则调用私有方法 warn(message) 打印警告信息。
3.1.2 ContextIdApplicationContextInitializer
先来看看 ContextIdApplicationContextInitializer 的源码,如下:


通过阅读上述源码,可以看出 ContextIdApplicationContextInitializer 是一个用于设置 Spring ApplicationContext ID 的应用上下文初始化器。其中,spring.application.name 属性用于创建 ID。如果该属性未设置,则使用 application。
我们在 initialize 方法中,还看到了如下的代码:
applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId);
这里就是将一个名为 ContextId 的类注册为单例对象,并将其存储在 Spring 的 ApplicationContext 中。然后我们就可以在应用程序的不同部分共享和重用同一个 ContextId 实例,而无需每次都创建新的实例。
3.1.3 DelegatingApplicationContextInitializer
同样先来看看 DelegatingApplicationContextInitializer 的源码,如下截图:

通过阅读该类的 initialize 方法,我们可以看出 DelegatingApplicationContextInitializer 初始化工作是委托给其他在 context.initializer.classes 环境属性下指定的应用上下文初始化器进行的。
下面的 3.3 小节,我们在自定义 ApplicationContext 初始化器实现 时就会用到。
3.1.4 RSocketPortInfoApplicationContextInitializer
无需多言,直接查看 RSocketPortInfoApplicationContextInitializer 的源码,如下:
public class RSocketPortInfoApplicationContextInitializerimplements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {applicationContext.addApplicationListener(new Listener(applicationContext));}// 省略。。。
}
阅读上述的 initialize 方法,可以看到这里向应用上下文中添加了一个 ApplicationListener,而这个 Listener 是 RSocketPortInfoApplicationContextInitializer 中的一个静态内部类。
继续阅读 Listener 的源码:

Listener 是用来监听 RSocketServerInitializedEvent 事件,该事件是在应用程序上下文刷新且 RSocketServer 准备就绪后发布的。
继续查看 onApplicationEvent 方法,我们可以看出该监听器是用来设置 RSocketServer 服务器实际监听的端口的环境属性。属性 local.rsocket.server.port 可以直接使用 @Value 注入到测试中,也可以通过 Environment 获取。另外该属性会自动向上传播到任何父上下文。
3.1.5 ServerPortInfoApplicationContextInitializer
同样还是从 ServerPortInfoApplicationContextInitializer 源码入手,如下所示:

通过阅读上面的 initialize 方法,可以看到这里也是比较简单,直接向应用上下文中添加了一个 ApplicationListener ,当然这个应用事件监听器比较特殊,就是其本身,因为 ServerPortInfoApplicationContextInitializer 实现了 ApplicationListener 接口。
该 ApplicationListener 监听的事件是 WebServerInitializedEvent,它是一个在 WebServer 准备就绪时发布的事件。
我们继续阅读 onApplicationEvent 方法的源码:

我们来简单总结如下:
该应用事件监听器用于设置 WebServer 服务器实际监听的端口的环境属性。属性 local.server.port 【如果 WebServerInitializedEvent 有一个服务器命名空间,它将被用来构造属性名称。例如,“management” actuator 上下文将具有属性名称 local.management.port】可以直接使用 @Value 注入到测试中,也可以通过 Environment 获取。该属性同样会自动向上传播到任何父上下文。
Actuator 是 Spring Boot 提供的一个开发库,它允许开发人员在运行时监控和管理应用程序。通过 Actuator,你可以查看应用程序的运行状况、性能指标、日志信息等。同时,它也提供了一些内置的管理端点,如健康检查、环境信息、应用信息等,方便开发人员进行调试和监控。Actuator 还提供了扩展机制,允许你自定义管理端点,以满足特定的需求。
3.2 spring-boot-autoconfigure 子模块中内置的实现类
同样我们先看截图:

从上图中可以看出,spring-boot-autoconfigure 子模块中配置的 ApplicationContextInitializer 实现有 2 个,下面来简单介绍下:
3.2.1 SharedMetadataReaderFactoryContextInitializer
SharedMetadataReaderFactoryContextInitializer 是一个应用上下文初始化器,主要作用是在 Spring 应用程序上下文创建之初,初始化一个共享的 MetadataReaderFactory 实例到在 Spring 应用上下文中。这样,在整个应用程序生命周期内,不同的组件在需要读取类的元数据时,都可以使用一个共享的 MetadataReaderFactory 实例,而无需每次都创建新的实例。
在 Spring 中,元数据(metadata)是用来描述 Bean 信息的数据,例如类名、方法名、属性名等。在应用程序运行时,Spring 会读取这些元数据来创建和管理 Bean。而
MetadataReaderFactory就是负责读取和解析类的元数据,比如注解、类属性等。
这块的逻辑比较复杂,Huazie 后续将再出一篇博文详细分析,敬请期待!
3.2.2 ConditionEvaluationReportLoggingListener
ConditionEvaluationReportLoggingListener 是一个用于将 ConditionEvaluationReport 写入日志的应用上下文初始化器,该应用上下文初始化器并不打算在多个应用程序上下文实例之间共享。
当 Spring 应用程序上下文初始化时,它会评估所有使用条件注解的 bean 定义和配置。这些条件可能基于类是否存在、特定的属性设置、其他 bean 是否存在等。ConditionEvaluationReport 记录了每个条件注解的评估结果,包括哪些条件通过了(即 bean 或配置被创建或执行了),哪些条件没有通过(即 bean 或配置被跳过了)。
ConditionEvaluationReport 的评估结果报告默认将以 DEBUG 级别进行记录。崩溃报告会触发 info 级别的输出,建议再次运行并启用 debug 级别以显示报告。
这块的逻辑也比较复杂,Huazie 后续也会出一篇博文详细介绍下,大家可以期待一下。
3.3 自定义应用上下文初始化器实现
上面 Huazie 同大家一起分析了 Spring Boot 中一些内置的应用上下文初始化器实现,相信对于如何实现 ApplicationContextInitializer 接口,已经有了较为深入的了解。
3.3.1 定义 DemoApplicationContextInitializer
那下面就让我们自定义 ApplicationContext 初始化器实现,如下所示:
public class DemoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {private int order = 0;@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {User user = new User("Huazie", 18);applicationContext.getBeanFactory().registerSingleton(User.class.getName(), user);}public void setOrder(int order) {this.order = order;}@Overridepublic int getOrder() {return this.order;}}
上述 DemoApplicationContextInitializer 的 initialize 方法中,我们注册了一个 User 类的单例 Bean。
3.3.2 添加 DemoApplicationContextInitializer
现在自定义的应用上下文初始化器有了,我们该如何添加它呢?
通过阅读 SpringApplication 的源码 和 本篇 3.1.3 小节的介绍,我们可以总结如下的三种方式:
-
在
META-INF/spring.factories中添加org.springframework.context.ApplicationContextInitializer的配置。这种方式,我们从 《ApplicationContextInitializer 详解》 的 3.2 小节可见一斑。org.springframework.context.ApplicationContextInitializer=com.example.demo.DemoApplicationContextInitializer -
通过
SpringApplication中的addInitializers方法添加。其实这里在笔者的《SpringApplication 的定制化介绍》中的 1.6 小节也提及过。SpringApplication springApplication = new SpringApplication(DemoApplication.class); springApplication.addInitializers(new DemoApplicationContextInitializer()); // 其他省略。。。 -
在 application.properties 中添加
context.initializer.classes的属性配置。这里实际上来源于 3.1.3 小节的 DelegatingApplicationContextInitializer。# 逗号分隔的类名列表 context.initializer.classes=com.example.demo.DemoApplicationContextInitializer在 application.yml 中添加
context.initializer.classes的属性配置# 在 YAML 中,数组或列表元素使用 - 符号来定义 context: initializer: classes: - com.example.demo.DemoApplicationContextInitializer
3.3.3 实际演示
我们采用第三种添加方式,配置截图如下:

添加如下自测类【用来演示获取在 DemoApplicationContextInitializer 中注册的 User 类的单例 Bean 对象】:
import com.example.demo.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class DemoApplicationTests {@Autowiredprivate User user;@Testpublic void test() {System.out.println("User = " + user);}
}
我们来看看运行结果,如下所示:

从上图可以看出,我们自定义的应用上下文初始化器实现显然已经执行了,并且成功注册了 User 类的单例 Bean 对象。
四、总结
本篇 Huazie 带大家一起分析了 Spring Boot 中预置的应用上下文初始化器实现,然后自定义了一个应用上下文初始化器实现类,进一步加深了对 Spring Boot 初始化应用上下文过程的了解,为后续的启动运行过程的理解打下了坚实的基础。
相关文章:
【Spring Boot 源码学习】深入应用上下文初始化器实现
《Spring Boot 源码学习系列》 深入应用上下文初始化器实现 一、引言二、往期内容三、主要内容3.1 spring-boot 子模块中内置的实现类3.1.1 ConfigurationWarningsApplicationContextInitializer3.1.2 ContextIdApplicationContextInitializer3.1.3 DelegatingApplicationConte…...
【Docker】一文趣谈Docker
🏡浩泽学编程:个人主页 🔥 推荐专栏:《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 🛸学无止境,不骄不躁,知行合一 文章目录 …...
代码随想录day19(2)二叉树:二叉树的最大深度(leetcode104)
题目要求:求出二叉树的最大深度 思路:首先要区分二叉树的高度与深度。二叉树的高度是任一结点到叶子结点的距离,而二叉树的深度指的是任一节点到根节点的距离(从1开始)。所以求高度使用后序遍历(从下往上&…...
Lua中文语言编程源码-第五节,更改lcorolib.c协程库函数, 使Lua加载中文库关键词(与所有的基础库相关)
源码已经更新在CSDN的码库里: git clone https://gitcode.com/funsion/CLua.git 在src文件夹下的lcorolib.c协程库函数,Coroutine Library:表明这个C源文件实现了Lua的协程库(Coroutine Library),即提供了…...
Docker学习之数据管理(超详解析)
Docker存储资源类型: 用户在使用 Docker 的过程中,势必需要查看容器内应用产生的数据,或者需要将容器内数据进行备份,甚至多个容器之间进行数据共享,这必然会涉及到容器的数据管理: (1ÿ…...
FDTD液晶折射率各项异性表示方法
由于FDTD的数据都是沿坐标轴的,各向异性材料的参数也需要根据坐标轴来输入。 首先要了解坐标变换。 坐标变换 这里以二维坐标变化为例。 矢量下我们可以发现OP可在两个坐标系下分别表示 接下来将两个坐标相互关联,这里以Xb举例,Yb同理 注…...
RoketMQ主从搭建
vim /etc/hosts# IP与域名映射,端口看自己的#nameserver 192.168.126.132 rocketmq-nameserver1 192.168.126.133 rocketmq-nameserver2# 注意主从节点不在同一个主机上 #broker 192.168.126.132 rocketmq-master1 192.168.126.133 rocketmq-master2#broker 192.168…...
Linux网络瑞士军刀 nc(netcat)
1.命令简介 nc(netcat)是一个短小精悍、功能实用、简单可靠的网络工具,主要有如下作用: (1)端口侦听,nc 可以作为 server 以 TCP 或 UDP 方式侦听指定端口; (2&#x…...
1.Spring入门
1.1 Spring简介 Spring是一个轻量级Java 企业级应用程序开发框架,目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。它是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架,为开发Java应用程序提供全面的基础架构支持。 Spring Fra…...
【JavaEE Spring 项目】消息队列的设计
消息队列的设计 一、消息队列的背景知识二、需求分析核心概念⼀个⽣产者, ⼀个消费者N 个⽣产者, N 个消费者Broker Server 中的相关概念核⼼ API交换机类型 (Exchange Type)持久化⽹络通信消息应答 三、 模块划分四、 项⽬创建五、创建核心类创建 Exchange创建 MSGQUeue创建 B…...
SpringFramework学习笔记(Spring IoC,aop,tx)
SpringFramework 本篇笔记是基于尚硅谷学习资料的整理,涉及到其笔记的简化,补充,以及我在学习中遇到的与无法理解的问题及解决,如果想看完整及后续的笔记,可以去https://www.wolai.com/v5Kuct5ZtPeVBk4NBUGBWF查看官方…...
口腔管理平台 |基于springboot框架+ Mysql+Java+B/S结构的口腔管理平台 设计与实现(可运行源码+数据库+lw文档)
推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 会员功能 系统功能设计 数据库E-R图设计 lunwen参考…...
【设计模式】Java 设计模式之工厂模式(Factory Pattern)
工厂模式(Factory Pattern)深入解析 一、工厂模式概述 工厂模式是一种创建型设计模式,它提供了一种封装对象创建过程的方式,将对象的创建与使用分离。工厂模式的核心思想是将“实例化对象”的操作与“使用对象”的操作分开&…...
安卓UI面试题 36-40
36. 简述 getDimension、getDimensionPixelOffset 和 getDimensionPixelSize 三者的区别? 相同点 单位为dp/sp时,都会乘以density,单位为px则不乘不同点 1、getDimension返回的是float值 2、getDimensionPixelSize,返回的是int值,float转成int时,四舍五入 3、getDimensio…...
Java有哪些常用的集合?
1、典型回答 在 Java 中,常用的集合有以下几个: 列表(List):有序集合,可以包含重复元素。常见实现类有 ArrayList、LinkedList、 Vector 等集合(Set):无序集合,不允许包含重复元素。常见实现类有 HashSet、…...
虚拟机网络链接
在虚拟网络设置中找到如下界面: "子网 IP" 192.168.79.0/24 表示一个局域网络,它有254个可能的IP地址可供分配(192.168.79.1到192.168.79.254),255.255.255.0 是子网掩码,定义了网络和主机部分。…...
代码随想录阅读笔记-字符串【反转字符串】
题目 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 你可以假设数组中的所有字符都是 ASCII 码表中的可打印…...
4. Linux文件属性和目录系列
在 Linux 系统中,文件和目录是基本的文件系统组成部分。文件系统是用于组织和存储文件的一种结构,而文件和目录则是文件系统的核心元素。以下是对 Linux 文件和目录的详细解释: 1. 文件(File) 在 Linux 中,文件是数据的集合,可以是文本文件、二进制文件、设备文件等。…...
Linux第78步_使用原子整型操作来实现“互斥访问”共享资源
使用原子操作来实现“互斥访问”LED灯设备,目的是每次只允许一个应用程序使用LED灯。 1、创建MyAtomicLED目录 输入“cd /home/zgq/linux/Linux_Drivers/回车” 切换到“/home/zgq/linux/Linux_Drivers/”目录 输入“mkdir MyAtomicLED回车”,创建MyA…...
C++——C++11(3)
C——C11(3) lambda表达式(匿名的仿函数对象)一些注意点lambda捕捉列表[][&][this] lambda的赋值 function包装器function成员函数的包装 bind绑定参数 我们今天接着来了解一下C11一些新的特性,如果还没有看过上两…...
Win10家庭版别再卡了!保姆级教程:手动修复gpedit.msc路径,彻底关闭Antimalware Service
Win10家庭版性能优化实战:精准修复组策略路径与系统服务调优每次游戏激战正酣时突然卡顿,或是视频渲染到关键时刻系统响应迟缓,很多Win10家庭版用户都遭遇过这类困扰。任务管理器里那个名为"Antimalware Service Executable"的进程…...
亚马逊卖家公开信息数据提取:反爬攻防战与 Python 批量采集实战
摘要: 批量获取亚马逊(Amazon)第三方卖家的商业名称、信用代码和注册地址等信息,对于跨境 B2B 拓客和供应链分析具有重要意义。然而,亚马逊的 Cloudflare 盾和 Robot 验证码构成了极高的反爬门槛。本文将深度解析亚马逊…...
环境光遮蔽(Ambient Occlusion):揭秘那个让虚拟世界“有重量感“的阴影魔法
一、一个让我"开窍"的老木匠故事 我有个朋友是传统家具的修复师,他给我讲过一个让我至今难忘的故事。他说他刚入行时跟着一位 70 多岁的老木匠师父学习——师父让他做的第一件事不是雕花、不是榫卯——而是"看阴影"——这个看似奇怪的训练改变了…...
App Inventor蓝牙调试避坑指南:从连接失败到数据乱码,一次讲清所有常见问题
App Inventor蓝牙调试避坑指南:从连接失败到数据乱码的实战解决方案在移动应用开发领域,蓝牙通信一直是实现设备间短距离数据交换的核心技术之一。对于使用App Inventor的开发者而言,蓝牙模块提供了无需复杂编码即可实现无线通信的便捷途径。…...
浏览器 Profile 环境排查:Cookie、LocalStorage、网络出口与自动化任务配置清单
一、为什么浏览器环境经常“今天能用,明天失效”很多团队遇到登录状态丢失、页面配置异常、自动化任务失败时,会先怀疑网络、脚本或系统本身。但在实际项目里,问题经常不是单点故障,而是浏览器环境缺少稳定管理:对象常…...
从入门到实践:EEG公开数据集分类与应用场景全解析
1. EEG公开数据集入门指南刚接触脑电信号分析的研究者,常常会被一个问题困扰:"我应该从哪里获取可靠的EEG数据?"作为一个在这个领域摸爬滚打多年的研究者,我完全理解这种困惑。记得我第一次接触EEG研究时,光…...
潮州东方轻奢风全屋高定找哪家
开篇引言根据《2026年中国全屋定制行业发展报告》,潮州市全屋定制市场规模同比增长38%,其中全屋高端定制细分市场同比增长52%。目前,潮州市家庭全屋定制需求占比72%,高端定制需求占比45%。为了帮助潮州市消费者选择合规、靠谱、差…...
三步实现跨架构程序兼容:Box64高效架构转换指南
三步实现跨架构程序兼容:Box64高效架构转换指南 【免费下载链接】box64 Box64 - Linux Userspace x86_64 Emulator with a twist, targeted at ARM64, RV64 and LoongArch Linux devices 项目地址: https://gitcode.com/gh_mirrors/bo/box64 你是否曾在ARM64…...
航空航天为什么离不开高强镁合金?国产替代到哪一步了
飞机每减重一千克,全年大约节省四千两百美元的燃油费用——这是航空工程师熟悉的经验值。在商业航空领域,这个数字还只是财务账;在战斗机、导弹和卫星的世界里,减重的收益被换算成更远的航程、更大的载荷、更高的机动性࿰…...
Gofile批量下载自动化工具:5步实现高效文件管理解决方案
Gofile批量下载自动化工具:5步实现高效文件管理解决方案 【免费下载链接】gofile-downloader Download files from https://gofile.io 项目地址: https://gitcode.com/gh_mirrors/go/gofile-downloader 在当今数字化工作环境中,技术团队经常需要从…...
