Spring Boot启动过程: 从new SpringApplication到run(),这中间到底发生了什么?
Spring Boot启动过程: 从new SpringApplication到run()这中间到底发生了什么引言: 一行代码背后的千山万水每个Spring Boot应用的入口都是这样一行代码:SpringApplication.run(Application.class, args);看似简单背后却是Spring团队十余年的设计积累。从推断应用类型到加载自动配置从启动内嵌Web服务器到刷新应用上下文整个过程涉及数十个步骤和扩展点。理解这个启动流程不仅能让你在面试中对答如流更能在排查启动故障、优化启动性能、扩展框架功能时游刃有余。本文将完整的启动过程拆解为11个关键步骤配合源码分析和时序图让你彻底掌握Spring Boot的启动魔法。一、启动流程全景图new SpringApplication()1. 推断应用类型2. 加载初始化器ApplicationContextInitializer3. 加载监听器ApplicationListener4. 推断主类run() 方法开始5. 准备环境Environment6. 打印Banner7. 创建应用上下文ApplicationContext8. 准备上下文postProcessApplicationContext9. 刷新上下文refreshContext10. 执行RunnerCommandLineRunner11. 发布已启动事件二、两大阶段: 构造与运行WebServerApplicationContextEnvironmentSpringApplicationmain方法WebServerApplicationContextEnvironmentSpringApplicationmain方法 阶段1: new SpringApplication() 阶段2: run() new SpringApplication(primarySources)1. 推断应用类型(WebFlux/Servlet/None)2. 加载ApplicationContextInitializer3. 加载ApplicationListener4. 推断主类(main方法所在类)run(args)5. 创建并准备Environment6. 创建ApplicationContext7. 准备上下文8. 刷新上下文(Spring核心启动)9. 启动内嵌Web服务器10. 执行Runner11. 返回上下文三、详细步骤拆解3.1 步骤1: 推断应用类型/** * SpringApplication 构造器中第一步: 推断应用类型 */ public class Step1_InferApplicationType { // 源码位置: SpringApplication.deduceWebApplicationType() // // private WebApplicationType deduceWebApplicationType() { // // 检查类路径中是否存在特定类 // if (ClassUtils.isPresent( // org.springframework.web.reactive.DispatcherHandler, null) // !ClassUtils.isPresent( // org.springframework.web.servlet.DispatcherServlet, null)) { // return WebApplicationType.REACTIVE; // WebFlux // } // for (String className : SERVLET_INDICATOR_CLASSES) { // if (!ClassUtils.isPresent(className, null)) { // return WebApplicationType.NONE; // 非Web应用 // } // } // return WebApplicationType.SERVLET; // Servlet Web(默认) // } public static void main(String[] args) { System.out.println( 推断应用类型 \n); System.out.println(判断逻辑:); System.out.println(1. 有 DispatcherHandler 且无 DispatcherServlet); System.out.println( - REACTIVE (WebFlux应用)); System.out.println(2. 缺少 javax.servlet.Servlet 或 DispatcherServlet); System.out.println( - NONE (非Web应用)); System.out.println(3. 其他情况); System.out.println( - SERVLET (传统Servlet Web应用)\n); System.out.println(这个判断决定了:); System.out.println(- 创建哪种 ApplicationContext); System.out.println(- 是否启动内嵌Web服务器); System.out.println(- 加载哪些Web相关的自动配置); } }3.2 步骤2-3: 加载初始化器与监听器(SPI机制)/** * SpringApplication 构造器第二步、第三步 * 通过 SpringFactoriesLoader 加载初始化器和监听器 */ public class Step2_LoadInitializersAndListeners { // 源码位置: SpringApplication 构造器 // // public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) { // this.resourceLoader resourceLoader; // this.primarySources new LinkedHashSet(Arrays.asList(primarySources)); // this.webApplicationType deduceWebApplicationType(); // // // 步骤2: 从spring.factories加载初始化器 // this.bootstrapRegistryInitializers // getBootstrapRegistryInitializersFromSpringFactories(); // setInitializers( // getSpringFactoriesInstances(ApplicationContextInitializer.class)); // // // 步骤3: 从spring.factories加载监听器 // setListeners( // getSpringFactoriesInstances(ApplicationListener.class)); // // // 步骤4: 推断主类 // this.mainApplicationClass deduceMainApplicationClass(); // } public static void main(String[] args) { System.out.println( 加载初始化器与监听器 \n); System.out.println(加载机制: SpringFactoriesLoader); System.out.println(从所有jar包的 META-INF/spring.factories 中读取\n); System.out.println(spring-boot.jar!/META-INF/spring.factories 内容:); System.out.println(ApplicationContextInitializer:\\); System.out.println( org.springframework.boot.context.); System.out.println( ConfigurationWarningsApplicationContextInitializer,\\); System.out.println( org.springframework.boot.context.); System.out.println( ContextIdApplicationContextInitializer,\\); System.out.println( ...\n); System.out.println(ApplicationListener:\\); System.out.println( org.springframework.boot.context.config.); System.out.println( ConfigFileApplicationListener,\\); System.out.println( org.springframework.boot.context.logging.); System.out.println( LoggingApplicationListener,\\); System.out.println( ...\n); System.out.println(这些组件在启动各阶段被回调实现功能扩展); } }3.3 步骤4: 推断主类/** * 推断主类: 通过调用栈找到main方法所在的类 */ public class Step4_DeduceMainClass { // 源码逻辑: // private Class? deduceMainApplicationClass() { // try { // StackTraceElement[] stackTrace new RuntimeException().getStackTrace(); // for (StackTraceElement element : stackTrace) { // if (main.equals(element.getMethodName())) { // return Class.forName(element.getClassName()); // } // } // } catch (ClassNotFoundException e) { // // 忽略 // } // return null; // } public static void main(String[] args) { System.out.println( 推断主类 \n); System.out.println(方法: 创建一个RuntimeException分析调用栈); System.out.println(查找: 栈中包含 main 方法的类); System.out.println(结果: 就是 SpringBootApplication 标注的类\n); System.out.println(作用:); System.out.println(- 作为primarySources传递给ApplicationContext); System.out.println(- 用于日志输出和Banner信息); } }3.4 步骤5: 准备环境/** * run() 方法中的关键步骤: 准备Environment */ public class Step5_PrepareEnvironment { // 源码: SpringApplication.prepareEnvironment() // // private ConfigurableEnvironment prepareEnvironment( // SpringApplicationRunListeners listeners, // DefaultBootstrapContext bootstrapContext, // ApplicationArguments applicationArguments) { // // // 5.1 创建Environment // ConfigurableEnvironment environment getOrCreateEnvironment(); // // // 5.2 配置Environment // configureEnvironment(environment, applicationArguments.getSourceArgs()); // // // 5.3 将spring.main的配置绑定到SpringApplication // ConfigurationPropertySources.attach(environment); // // // 5.4 发布环境准备事件 // listeners.environmentPrepared(bootstrapContext, environment); // // // 5.5 将spring.main配置应用到SpringApplication // DefaultPropertiesPropertySource.moveToEnd(environment); // // return environment; // } public static void main(String[] args) { System.out.println( 准备Environment \n); System.out.println(子步骤:); System.out.println(5.1 创建Environment(Standard或Reactive)); System.out.println(5.2 配置PropertySources和Profiles); System.out.println( - 读取命令行参数(--server.port8080)); System.out.println( - 设置激活的Profile(spring.profiles.active)); System.out.println(5.3 附加ConfigurationPropertySources); System.out.println(5.4 发布ApplicationEnvironmentPreparedEvent); System.out.println( - ConfigFileApplicationListener 在此读取 application.yml); System.out.println(5.5 应用 spring.main 配置到 SpringApplication\n); System.out.println(关键: application.yml/properties 文件在此阶段加载!); } }3.5 步骤6-7: 创建并准备上下文/** * 创建应用上下文并准备 */ public class Step6_CreateAndPrepareContext { // 源码: SpringApplication.createApplicationContext() // // protected ConfigurableApplicationContext createApplicationContext() { // return this.applicationContextFactory.create(this.webApplicationType); // } // // 根据webApplicationType创建不同的上下文: // SERVLET - AnnotationConfigServletWebServerApplicationContext // REACTIVE - AnnotationConfigReactiveWebServerApplicationContext // NONE - AnnotationConfigApplicationContext public static void main(String[] args) { System.out.println( 创建并准备上下文 \n); System.out.println(步骤6: 创建ApplicationContext); System.out.println( 根据推断的类型创建对应的上下文实现\n); System.out.println(步骤7: prepareContext - 准备上下文); System.out.println( 7.1 设置Environment); System.out.println( 7.2 后置处理(postProcessApplicationContext)); System.out.println( 7.3 执行ApplicationContextInitializer); System.out.println( 7.4 发布ApplicationContextInitializedEvent); System.out.println( 7.5 注册启动源(primarySources)); System.out.println( 7.6 发布ApplicationPreparedEvent); } }3.6 步骤8: 刷新上下文(Spring核心启动)/** * refreshContext: Spring Framework的核心启动流程 * * 这是整个启动过程中最关键、最复杂的步骤 */ public class Step8_RefreshContext { // 源码: SpringApplication.refreshContext() // - AbstractApplicationContext.refresh() // // public void refresh() throws BeansException { // synchronized (this.startupShutdownMonitor) { // // 1. 准备刷新 // prepareRefresh(); // // // 2. 获取BeanFactory // ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory(); // // // 3. 准备BeanFactory // prepareBeanFactory(beanFactory); // // // 4. BeanFactory后置处理 // postProcessBeanFactory(beanFactory); // // // 5. 执行BeanFactoryPostProcessor // invokeBeanFactoryPostProcessors(beanFactory); // // 这里会执行 ConfigurationClassPostProcessor // // 完成 Configuration 类的解析和 ComponentScan // // // 6. 注册BeanPostProcessor // registerBeanPostProcessors(beanFactory); // // // 7. 初始化MessageSource // initMessageSource(); // // // 8. 初始化事件广播器 // initApplicationEventMulticaster(); // // // 9. 子类扩展点(onRefresh) // onRefresh(); // // ServletWebServerApplicationContext 在这里启动内嵌Web服务器! // // // 10. 注册监听器 // registerListeners(); // // // 11. 实例化所有非懒加载的单例Bean // finishBeanFactoryInitialization(beanFactory); // // Service、Controller、Repository 等Bean在这里创建 // // // 12. 完成刷新 // finishRefresh(); // } // } public static void main(String[] args) { System.out.println( refresh() 12个核心步骤 \n); System.out.println(1. prepareRefresh()); System.out.println( - 设置启动时间、状态标记); System.out.println( - 验证必要属性\n); System.out.println(2. obtainFreshBeanFactory()); System.out.println( - 获取BeanFactory(Spring容器)\n); System.out.println(3. prepareBeanFactory()); System.out.println( - 设置类加载器、表达式解析器); System.out.println( - 注册默认BeanPostProcessor\n); System.out.println(4. postProcessBeanFactory()); System.out.println( - 子类扩展点(Web上下文扫描特殊Bean)\n); System.out.println(5. invokeBeanFactoryPostProcessors() ★★★); System.out.println( - 执行所有BeanFactoryPostProcessor); System.out.println( - ConfigurationClassPostProcessor 解析 Configuration); System.out.println( - ComponentScan 扫描Bean定义); System.out.println( - EnableAutoConfiguration 加载自动配置); System.out.println( - 这是自动配置生效的关键步骤!\n); System.out.println(6. registerBeanPostProcessors()); System.out.println( - 注册BeanPostProcessor到容器\n); System.out.println(7-10. 初始化辅助组件); System.out.println( - MessageSource、事件广播器、Web服务器\n); System.out.println(11. finishBeanFactoryInitialization() ★★★); System.out.println( - 实例化所有单例Bean); System.out.println( - 处理循环依赖(三级缓存)); System.out.println( - 这是最耗时的步骤!\n); System.out.println(12. finishRefresh()); System.out.println( - 发布ContextRefreshedEvent); } }3.7 步骤9: 启动内嵌Web服务器/** * Web服务器启动细节 */ public class Step9_StartWebServer { // 源码: ServletWebServerApplicationContext.onRefresh() // - createWebServer() // - webServer.start() // // private void createWebServer() { // WebServer webServer this.webServer; // ServletContext servletContext getServletContext(); // if (webServer null servletContext null) { // // 获取WebServerFactory(如TomcatServletWebServerFactory) // ServletWebServerFactory factory getWebServerFactory(); // // // 创建Web服务器(内嵌Tomcat/Jetty/Undertow) // this.webServer factory.getWebServer(getSelfInitializer()); // } // // 启动Web服务器 // initPropertySources(); // } public static void main(String[] args) { System.out.println( 启动内嵌Web服务器 \n); System.out.println(触发时机: refresh() 中的 onRefresh() 步骤\n); System.out.println(执行流程:); System.out.println(1. 获取 ServletWebServerFactory Bean); System.out.println( - 根据类路径自动选择:); System.out.println( * Tomcat: spring-boot-starter-web 默认); System.out.println( * Jetty: 排除Tomcat引入Jetty); System.out.println( * Undertow: 排除Tomcat引入Undertow); System.out.println(2. 创建 WebServer 实例); System.out.println(3. 配置 Servlet、Filter、Listener); System.out.println(4. 调用 webServer.start() 启动服务); System.out.println(5. 发布 ServletWebServerInitializedEvent\n); System.out.println(服务器启动后:); System.out.println(- 端口已绑定); System.out.println(- DispatcherServlet 已就绪); System.out.println(- 可以接收HTTP请求); } }3.8 步骤10-11: Runner与完成事件/** * 启动的最后步骤: 执行Runner并发布完成事件 */ public class Step10_RunnersAndFinish { // 源码: SpringApplication.callRunners() // - ApplicationRunner.run() 和 CommandLineRunner.run() public static void main(String[] args) { System.out.println( 执行Runner \n); System.out.println(Runner执行顺序:); System.out.println(1. ApplicationRunner (优先级高)); System.out.println( - 接收 ApplicationArguments (已解析的参数)); System.out.println(2. CommandLineRunner (优先级低)); System.out.println( - 接收 String[] (原始参数)\n); System.out.println(使用示例:); System.out.println(Component); System.out.println(public class DataInitializer implements CommandLineRunner {); System.out.println( public void run(String... args) {); System.out.println( // 初始化数据、预热缓存); System.out.println( }); System.out.println(}\n); System.out.println(最后: 发布 ApplicationStartedEvent); System.out.println( 发布 ApplicationReadyEvent); System.out.println( Spring Boot启动完成!); } }四、扩展点时机汇总/** * Spring Boot启动过程的完整扩展点 */ public class ExtensionPointsSummary { public static void main(String[] args) { System.out.println( 启动过程扩展点执行顺序 \n); String[] timeline { 1. SpringApplicationRunListener.starting(), 2. ApplicationContextInitializer.initialize(), 3. SpringApplicationRunListener.environmentPrepared(), 4. SpringApplicationRunListener.contextPrepared(), 5. SpringApplicationRunListener.contextLoaded(), , refresh() 阶段 , 6. BeanFactoryPostProcessor.postProcessBeanFactory(), 7. PostConstruct, 8. InitializingBean.afterPropertiesSet(), 9. BeanPostProcessor (贯穿Bean创建过程), , refresh() 之后 , 10. SpringApplicationRunListener.started(), 11. ApplicationRunner.run(), 12. CommandLineRunner.run(), 13. SpringApplicationRunListener.ready(), }; for (String step : timeline) { System.out.println(step); } } }五、面试高频问题5.1 启动过程核心面试题/** * 面试高频问题与答案 */ public class InterviewQuestions { public static void main(String[] args) { System.out.println( 面试高频问题 \n); // Q1 System.out.println(Q1: Spring Boot启动过程?); System.out.println(A: 两大阶段11步:); System.out.println( 构造阶段: 推断类型、加载初始化器/监听器、推断主类); System.out.println( 运行阶段: 准备环境、创建上下文、准备上下文、); System.out.println( 刷新上下文(Spring核心)、启动Web服务器、); System.out.println( 执行Runner、发布完成事件\n); // Q2 System.out.println(Q2: 自动配置什么时候生效?); System.out.println(A: refresh()的invokeBeanFactoryPostProcessors()步骤); System.out.println( ConfigurationClassPostProcessor 解析 EnableAutoConfiguration); System.out.println( - AutoConfigurationImportSelector 加载 spring.factories); System.out.println( - 条件过滤后注册自动配置类的Bean定义\n); // Q3 System.out.println(Q3: Web服务器什么时候启动?); System.out.println(A: refresh()的onRefresh()步骤); System.out.println( ServletWebServerApplicationContext 会在此创建并启动); System.out.println( 内嵌Tomcat/Jetty/Undertow\n); // Q4 System.out.println(Q4: application.yml什么时候加载?); System.out.println(A: 准备环境阶段(步骤5)); System.out.println( ConfigFileApplicationListener 监听到环境准备事件); System.out.println( 读取 application.yml/properties 并添加到Environment); } }六、总结6.1 启动过程核心步骤速查| 步骤 | 做什么 | 关键点 ||------|--------|--------|| 推断类型 | 检查类路径 | 决定Context和WebServer类型 || 加载SPI组件 | 读spring.factories | 初始化器和监听器 || 准备环境 | 创建Environment | 加载application.yml || 创建上下文 | 根据类型new | 三种Context实现 || 准备上下文 | 设置属性 | 执行初始化器 ||刷新上下文|refresh()|Bean扫描、自动配置、单例实例化|| 启动WebServer | onRefresh() | 内嵌Tomcat启动 || 执行Runner | callRunners() | CommandLineRunner |6.2 关键类关系图SpringApplication ├── 创建时: 加载Initializer和Listener └── run()时: ├── 创建Environment ├── 创建ApplicationContext │ └── refresh() │ ├── BeanFactoryPostProcessor (自动配置生效) │ ├── onRefresh() (WebServer启动) │ └── finishBeanFactoryInitialization() (Bean实例化) └── 发布Ready事件---如果本文帮你理解了Spring Boot启动的全过程欢迎点赞收藏。有任何疑问欢迎评论区交流

相关新闻

B+Tree深度剖析: 高度为3的B+Tree能存多少条MySQL数据?(含计算过程)

B+Tree深度剖析: 高度为3的B+Tree能存多少条MySQL数据?(含计算过程)

BTree深度剖析: 高度为3的BTree能存多少条MySQL数据?(含计算过程) 引言: 一个高频面试题的数字推导 "MySQL一张表能存多少数据?" "BTree高度为3能存多少条记录?" 这是DBA和高级开发面试中的高频问题。很多人能回答"…

2026/10/15 13:47:22 阅读更多 →
索引失效避坑: 明明是等值查询,为何EXPLAIN显示走了全表扫描?

索引失效避坑: 明明是等值查询,为何EXPLAIN显示走了全表扫描?

索引失效避坑: 明明是等值查询,为何EXPLAIN显示走了全表扫描?引言: 一个让开发者怀疑人生的EXPLAIN你写了一个简单的等值查询,建了索引,满怀信心地执行EXPLAIN,结果type列赫然显示ALL——全表扫描。你反复检查SQL和索引…

2026/10/15 13:47:48 阅读更多 →
【JPCS出版】2026年工业工程与智能制造国际学术会议 (ICIEIM 2026)

【JPCS出版】2026年工业工程与智能制造国际学术会议 (ICIEIM 2026)

2026年工业工程与智能制造国际学术会议 (ICIEIM 2026) 2026 International Conference on Industrial Engineering and Intelligent Manufacturing 中国•大连 2026年11月13日-2026年11月15日 重要信息 会议官网:2026年工业工程与智能制造国际学术会…

2026/10/14 5:15:10 阅读更多 →

最新新闻

SpringBoot双模版电商系统设计与实现

SpringBoot双模版电商系统设计与实现

1. 项目概述:双模版电商系统的技术实现 这个SpringBoot零食商城系统是一个典型的轻量级电商解决方案,最显著的特点是采用了模块化设计,同时支持零食商城和花店管理两种业务模式。我在实际部署测试中发现,系统通过配置开关即可切换…

2026/10/15 13:47:17 阅读更多 →
DeepSeek模型本地部署与推理避坑指南

DeepSeek模型本地部署与推理避坑指南

简介:本资源是一份面向AI从业者、技术管理者与高校研究者的DeepSeek大模型内部科普培训材料,系统解析国产高性能大模型的技术架构、能力边界与落地路径。PPTX格式的单文件课件(27.18MB)结构清晰,涵盖DeepSeek-V3&#…

2026/10/15 13:47:17 阅读更多 →
Jev 估值 75 亿美元后,微软火速反击:数据之战下 API 通道如何选?TaoToken 统一 Key 实测

Jev 估值 75 亿美元后,微软火速反击:数据之战下 API 通道如何选?TaoToken 统一 Key 实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 13:47:17 阅读更多 →
物流中转站选址规划与运营实操:从选址到成本控制的全流程指南

物流中转站选址规划与运营实操:从选址到成本控制的全流程指南

1. 物流中转站选址与规划的核心逻辑1.1 为什么中转站选址是生死攸关的第一步做物流这行十几年,我见过太多项目死在选址上。一个物流中转站建起来,土地成本、建设成本、设备投入加起来动辄几百万甚至上千万,一旦位置选错,后面怎么优…

2026/10/15 13:47:17 阅读更多 →
异常检测实战:从统计基线到自适应建模的分层方法

异常检测实战:从统计基线到自适应建模的分层方法

1. 这不是“找bug”,而是让机器学会识别“不对劲”的直觉你有没有过这种感觉:在一堆整齐划一的数据里,突然冒出一个格格不入的点——它数值大得离谱,位置偏得诡异,行为模式完全不像其他样本?比如某天服务器…

2026/10/15 13:47:17 阅读更多 →
ponytail:把终端命令变成可复用技能的高效自动化工具

ponytail:把终端命令变成可复用技能的高效自动化工具

ponytail。第一次在同事的终端里看到这个词,我还以为是某个桌面对弈壁纸的花名。直到他现场敲了两行命令,把原本我得翻半天历史记录、拼接七八条命令才能完成的日志分析,变成了问候式的一行pt log --path access.log --top 5,我才…

2026/10/15 13:46:16 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →