版本背景SpringBoot2.x 核心容器Servlet 类型 Web 应用上下文对应 SpringBoot Servlet Web传统 Tomcat 嵌入式 web环境非响应式 Web (Reactive)。继承链AnnotationConfigServletWebServerApplicationContext→ServletWebServerApplicationContext→GenericWebApplicationContext→GenericApplicationContext→AbstractApplicationContext实现接口AnnotationConfigRegistry提供register()注册配置类、scan()扫描包能力。架构设计层面解析1. 定位与职责这是SpringBoot Servlet Web 场景的默认应用上下文由ApplicationContextFactory.Factory工厂进行实例化。融合两套能力父类ServletWebServerApplicationContext嵌入式 web 服务器能力refresh 流程中会创建 Tomcat/Jetty 等 web 容器是 SpringBoot 内置 web 服务的核心自身实现AnnotationConfigRegistry注解驱动配置能力等价于传统 Spring 的AnnotationConfigApplicationContext支持直接注册配置类、包路径扫描 Bean 定义抛弃 xml。对比AnnotationConfigApplicationContext普通非 web 注解容器Spring 原生AnnotationConfigServletWebServerApplicationContextSpringBoot 封装的 Servlet Web 注解容器AnnotationConfigReactiveWebServerApplicationContext响应式 web 容器2. 核心成员变量设计// 读取注解类把Configuration/Component类解析成BeanDefinitionprivatefinalAnnotatedBeanDefinitionReaderreader;// 类路径扫描器扫描包下Component等注解的类生成BeanDefinitionprivatefinalClassPathBeanDefinitionScannerscanner;// 缓存通过register()方法手动注册的配置Class集合privatefinalSetClass?annotatedClasses;// 缓存通过scan()传入的扫描包路径privateString[]basePackages;⚠️关键设计点register()、scan()没有立刻执行 Bean 定义注册只是把 class、package 暂存到成员变量真正执行扫描注册延迟到postProcessBeanFactory。为什么要延迟refresh()是父类AbstractApplicationContext定义的标准生命周期BeanFactory 还没完成初始化前不能向 BeanFactory 注册 BeanDefinition遵循 Spring 生命周期扩展点postProcessBeanFactory这是refresh()内部的标准回调时机允许子类对 beanFactory 做后置加工保证环境 Environment、BeanNameGenerator、ScopeMetadataResolver 全部设置完成后再执行扫描解析。3. 扩展点与设计模式模板方法模式继承AbstractApplicationContext的 refresh () 完整生命周期重写prepareRefresh、postProcessBeanFactory做子类定制逻辑父类控制主流程子类实现差异化工厂模式内部静态Factory实现ApplicationContextFactorySpringBoot 会根据WebApplicationType来选择实例化哪一种 ApplicationContextSERVLET/REACTIVE/NONE组合模式组合AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner自身不实现解析逻辑委托给这两个组件符合单一职责reader负责单个注解类解析注册scanner负责 classpath 包扫描配置透传设计setEnvironment/setBeanNameGenerator/setScopeMetadataResolver配置不仅设置给上下文同时同步委托给内部 reader 和 scanner保证解析行为统一。4. 与 SpringApplication 启动流程关系SpringBoot 启动时通过ApplicationContextFactory.Factory#create()构造该上下文之后执行 refresh ()refresh 内部链路refresh()→prepareRefresh()→postProcessBeanFactory()→ 执行 scan 和 register 加载 bean 定义 → 后续执行 Bean 实例化、创建嵌入式 Tomcat。注意构造函数// 传入配置类内部调用registerrefreshpublicAnnotationConfigServletWebServerApplicationContext(Class?...annotatedClasses)// 传入包路径内部调用scanrefreshpublicAnnotationConfigServletWebServerApplicationContext(String...basePackages)这两个构造方法手动调用 refresh ()日常 SpringApplication 启动时不会使用这两个构造SpringBoot 会调用无参构造统一外部调用 refresh。源码解析/** * SpringBoot Servlet Web环境注解驱动的应用上下文 * 1. 支持注解配置类register注册、包路径scan扫描 * 2. 继承ServletWebServerApplicationContext拥有创建嵌入式Tomcat等web服务器能力 * 3. 实现AnnotationConfigRegistry对齐AnnotationConfigApplicationContext的注解驱动API * 仅用于WebApplicationType.SERVLET场景 */publicclassAnnotationConfigServletWebServerApplicationContextextendsServletWebServerApplicationContextimplementsAnnotationConfigRegistry{/** * 注解Bean定义读取器解析单个Configuration、Component注解类生成BeanDefinition注册到容器 */privatefinalAnnotatedBeanDefinitionReaderreader;/** * classpath扫描器扫描指定包路径下带Component派生注解的类生成BeanDefinition */privatefinalClassPathBeanDefinitionScannerscanner;/** * 缓存调用register()传入的配置类延迟到postProcessBeanFactory阶段才真正注册 * LinkedHashSet保证顺序 */privatefinalSetClass?annotatedClasses;/** * 缓存调用scan()传入的扫描包路径延迟执行扫描 */privateString[]basePackages;/** * 无参构造SpringBoot框架启动时实际使用的构造函数 * 初始化reader、scanner初始化存储配置类的集合 */publicAnnotationConfigServletWebServerApplicationContext(){this.annotatedClassesnewLinkedHashSet();this.readernewAnnotatedBeanDefinitionReader(this);this.scannernewClassPathBeanDefinitionScanner(this);}/** * 指定BeanFactory的构造父类ServletWebServerApplicationContext支持传入自定义beanFactory * param beanFactory 自定义DefaultListableBeanFactory */publicAnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactorybeanFactory){super(beanFactory);this.annotatedClassesnewLinkedHashSet();this.readernewAnnotatedBeanDefinitionReader(this);this.scannernewClassPathBeanDefinitionScanner(this);}/** * 传入配置类的构造器【注意会直接执行refresh()】 * 一般不会被SpringBoot主流程调用多用于单元测试手动启动容器 * param annotatedClasses 需要注册的Configuration等注解配置类 */publicAnnotationConfigServletWebServerApplicationContext(Class?...annotatedClasses){this();// 将配置类存入缓存集合不是立刻注册BeanDefinitionthis.register(annotatedClasses);// 立刻触发完整Spring生命周期刷新this.refresh();}/** * 指定扫描包路径的构造器【注意会直接执行refresh()】 * 多用于手动编码启动web容器场景业务开发极少使用 * param basePackages 需要扫描的基础包路径 */publicAnnotationConfigServletWebServerApplicationContext(String...basePackages){this();// 包路径存入成员变量缓存不马上扫描this.scan(basePackages);this.refresh();}/** * 重写设置环境把Environment同步透传给内部reader和scanner * 保证扫描、解析注解时使用同一个Environment(profile、properties配置) * param environment 环境对象 */publicvoidsetEnvironment(ConfigurableEnvironmentenvironment){super.setEnvironment(environment);this.reader.setEnvironment(environment);this.scanner.setEnvironment(environment);}/** * 设置BeanName生成器同步给reader、scanner同时注册单例bean到beanFactory * Spring内部会使用这个BeanNameGenerator处理Configuration类命名 * param beanNameGenerator bean名称生成策略 */publicvoidsetBeanNameGenerator(BeanNameGeneratorbeanNameGenerator){this.reader.setBeanNameGenerator(beanNameGenerator);this.scanner.setBeanNameGenerator(beanNameGenerator);// 向beanFactory注册单例key是Spring内部固定常量供内部组件获取this.getBeanFactory().registerSingleton(org.springframework.context.annotation.internalConfigurationBeanNameGenerator,beanNameGenerator);}/** * 设置Scope元数据解析器同步透传给reader和scanner * 用于解析Scope注解处理singleton/prototype等作用域支持自定义scope解析 * param scopeMetadataResolver scope元解析器 */publicvoidsetScopeMetadataResolver(ScopeMetadataResolverscopeMetadataResolver){this.reader.setScopeMetadataResolver(scopeMetadataResolver);this.scanner.setScopeMetadataResolver(scopeMetadataResolver);}/** * AnnotationConfigRegistry接口实现注册注解配置类 * 【重要这里只是存入集合缓存并不会立刻解析注册BeanDefinition】 * 真正执行reader.register推迟到postProcessBeanFactory * param annotatedClasses 配置类数组 */publicfinalvoidregister(Class?...annotatedClasses){Assert.notEmpty(annotatedClasses,At least one annotated class must be specified);this.annotatedClasses.addAll(Arrays.asList(annotatedClasses));}/** * AnnotationConfigRegistry接口实现指定扫描包 * 【重要仅缓存包路径不会立刻执行扫描】 * scanner.scan(basePackages)推迟到postProcessBeanFactory生命周期回调 * param basePackages 待扫描包路径 */publicfinalvoidscan(String...basePackages){Assert.notEmpty(basePackages,At least one base package must be specified);this.basePackagesbasePackages;}/** * 重写父类AbstractApplicationContext#prepareRefresh * refresh()生命周期第一个阶段准备刷新上下文 * 清理scanner缓存scanner内部会缓存扫描过的元数据刷新前清空防止旧缓存干扰 */protectedvoidprepareRefresh(){this.scanner.clearCache();super.prepareRefresh();}/** * ✨核心扩展方法父类模板方法钩子 postProcessBeanFactory * 在refresh()中执行时机BeanFactory已经创建完成BeanDefinition还没有开始实例化bean * 这里才真正执行包扫描、注册配置类BeanDefinition * param beanFactory 已经初始化完成的bean工厂 */protectedvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory){// 调用父类ServletWebServerApplicationContext的后置处理super.postProcessBeanFactory(beanFactory);// 如果存在扫描包路径委托scanner执行类路径扫描注册BeanDefinitionif(this.basePackages!nullthis.basePackages.length0){this.scanner.scan(this.basePackages);}// 如果缓存了注册的配置类委托reader执行注册配置类的BeanDefinitionif(!this.annotatedClasses.isEmpty()){this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));}}/** * 内部静态工厂实现SpringBoot SPI接口 ApplicationContextFactory * SpringBoot通过SPI加载该Factory根据WebApplicationType选择创建对应上下文 */staticclassFactoryimplementsApplicationContextFactory{Factory(){}/** * 返回该上下文对应的Environment类型只有SERVLET类型web返回ApplicationServletEnvironment */publicClass?extendsConfigurableEnvironmentgetEnvironmentType(WebApplicationTypewebApplicationType){returnwebApplicationType!WebApplicationType.SERVLET?null:ApplicationServletEnvironment.class;}/** * 创建Servlet web对应的环境实例 ApplicationServletEnvironment */publicConfigurableEnvironmentcreateEnvironment(WebApplicationTypewebApplicationType){returnwebApplicationType!WebApplicationType.SERVLET?null:newApplicationServletEnvironment();}/** * 创建上下文实例只有SERVLET场景返回AnnotationConfigServletWebServerApplicationContext * SpringBoot启动流程会调用该方法拿到无参构造的上下文实例 */publicConfigurableApplicationContextcreate(WebApplicationTypewebApplicationType){returnwebApplicationType!WebApplicationType.SERVLET?null:newAnnotationConfigServletWebServerApplicationContext();}}}关键源码要点总结register ()/scan () 延迟执行是最大的特点很多人误以为调用register()就注册 Bean实际上只是放到集合等到postProcessBeanFactory才真正解析如果在 refresh 之前修改 environment、beanNameGenerator都会对这些配置类、扫描的 bean 生效。postProcessBeanFactory是什么时机refresh () 生命周期obtainFreshBeanFactory()→拿到全新 BeanFactory→postProcessBeanFactory(beanFactory)BeanDefinition 还没解析完成Bean 还没有实例化是修改 BeanFactory、追加 BeanDefinition 的标准扩展点。和父类分工ServletWebServerApplicationContext负责 web 服务器Tomcat 创建、onRefresh () 中启动 web 服务当前类只负责注解驱动 BeanDefinition 加载职责分离开闭原则。内部Factory是 SpringBoot SPI 机制META-INF/services 中配置ApplicationContextFactorySpringBoot 根据 web 应用类型选择实例化该容器、reactive 容器或者非 web 容器。两个带 refresh 的构造函数业务代码几乎不用主要用于单元测试手动启动嵌入式 web 容器SpringApplication.run 不会调用SpringApplication 自己调用无参构造外部统一调用 refresh ()。架构取舍Q为什么不直接在 register 方法中调用reader.register(clazz)非要缓存到 postProcessBeanFactory 再执行如果在 register 直接解析调用 register 的时候 BeanFactory 可能还没初始化完成用户可以多次 setEnvironment、setBeanNameGenerator这些配置可以在 register 之后、refresh 之前设置如果 register 立刻解析后面修改的配置不会生效完全遵循 Spring 统一生命周期和AbstractApplicationContext模板流程对齐保证 web 与非 web 容器行为一致。Q对比原生AnnotationConfigApplicationContext原生AnnotationConfigApplicationContextregister/scan 会立刻执行而本类做了延迟这是 SpringBoot 为 web 场景做的适配改动。
企业数字化 ERP 产品动态
相关推荐
3 步跑起 XHS-Downloader:批量下载无水印小红书作品教程 3 步跑起 XHS-Downloader:批量下载无水印小红书作品教程 【免费下载链接】XHS-Downloader 小红书(XiaoHongShu、RedNote)链接提取/作品采集工具 项目地址: https://gitcode.com/gh_mirrors/xh/XHS-Downloader
XHS-Downloader 是一个开… · 2026/11/4 6:15:23
Dism++ 免费指南:用一款绿色工具搞定系统清理与映像维护 Dism 免费指南:用一款绿色工具搞定系统清理与映像维护 【免费下载链接】Dism-Multi-language Dism Multi-language Support & BUG Report 项目地址: https://gitcode.com/gh_mirrors/di/Dism-Multi-language
C 盘可用空间被 WinSxS(Windows 的… · 2026/11/4 6:15:23
FanControl 风扇控制实战指南:20 分钟调好温度曲线,让风扇安静下来 FanControl 风扇控制实战指南:20 分钟调好温度曲线,让风扇安静下来 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode… · 2026/11/4 6:15:23
OpenClaw机械臂控制框架:从入门到实战 1. OpenClaw初探:一个机械臂控制框架的诞生第一次听说OpenClaw是在三年前的机器人开发者大会上。当时一位做工业自动化的同行在茶歇时神秘兮兮地掏出手机,给我看了一段视频——六轴机械臂正在以惊人的流畅度完成抓取动作,指尖的夹爪像人类手指… · 2026/11/4 20:51:33
架构设计核心思维与实践指南 1. 架构的本质与常见误区刚入行时我对"架构"这个词充满敬畏,总觉得是那些年薪百万的CTO才需要考虑的高深学问。直到自己负责的第一个系统因为设计缺陷半夜崩了三次,才真正理解架构不是挂在墙上的蓝图,而是每天在代码里呼吸的生命体… · 2026/11/4 20:51:33
Git官方文档全解析:从入门到高阶的完整指南 1. Git官方文档全景解读:从入门到高阶的完整指南作为分布式版本控制系统的实际行业标准,Git的官方文档体系堪称开发者必备的"生存手册"。不同于第三方教程的碎片化特点,官方文档以严谨性、完整性和权威性著称。但面对多达数十个手册… · 2026/11/4 20:51:33
MinIO对象存储实战:从部署到生产环境避坑指南 对象存储这个词,刚接触的时候觉得离自己挺远,总觉得那是大厂才折腾的东西。后来做几个内部项目,需要存用户上传的图片、日志归档、模型训练用的数据集,才发现用传统文件系统硬扛是真的难受——权限乱、扩容烦、备份靠手抄。MinIO … · 2026/11/4 20:51:33
AI驱动的三维漏洞感知系统:Capybara安全测试解析 1. 项目概述:当水豚学会渗透测试 去年夏天,安全研究员们发现了一个奇怪现象:某些企业级防火墙的0day漏洞报告突然激增,而提交者署名都是"Cappy_Research"。追踪IP地址后更令人震惊——这些报告全部来自Anthropic公司的云… · 2026/11/4 20:51:33
前端性能优化实战:从指标到工具链全解析 1. 为什么前端性能优化比以往更重要十年前我刚入行时,一个页面加载5秒都算正常。现在?用户会在3秒内关闭加载缓慢的网页。根据Google数据,页面加载时间从1秒增加到3秒时,跳出率提升32%。这背后是用户习惯的根本性改变——移动设备… · 2026/11/4 20:50:28
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38