带着问题看SpringBoot
带着问题看SpringBoot
1、Spring容器具体是什么?
跟进run方法,context = this.createApplicationContext(),得出容器是AnnotationConfigServletWebServerApplicationContext类。
SpringApplication.run(ServeroneApplication.class, args);
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();this.configureHeadlessProperty();SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();Collection exceptionReporters;try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);this.configureIgnoreBeanInfo(environment);Banner printedBanner = this.printBanner(environment);context = this.createApplicationContext();exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);this.refreshContext(context);this.afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}listeners.started(context);this.callRunners(context, applicationArguments);} catch (Throwable var10) {this.handleRunFailure(context, var10, exceptionReporters, listeners);throw new IllegalStateException(var10);}try {listeners.running(context);return context;} catch (Throwable var9) {this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);throw new IllegalStateException(var9);}}
protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");break;case REACTIVE:contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");break;default:contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");}} catch (ClassNotFoundException var3) {throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);}}return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);}
2、SpringBoot中Tomcat的启动流程。
2.1、跟进TomcatWebServer类的initialize() 方法,断点到logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));然后反向debug你可以看出Tomcat的初始化过程,是在容器执行run()方法的时候执行refresh()方法的this.onRefresh();的时候初始化的。
private void initialize() throws WebServerException {logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));synchronized(this.monitor) {try {this.addInstanceIdToEngineName();Context context = this.findContext();context.addLifecycleListener((event) -> {if (context.equals(event.getSource()) && "start".equals(event.getType())) {this.removeServiceConnectors();}});this.tomcat.start();this.rethrowDeferredStartupExceptions();try {ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());} catch (NamingException var5) {}this.startDaemonAwaitThread();} catch (Exception var6) {this.stopSilently();this.destroySilently();throw new WebServerException("Unable to start embedded Tomcat", var6);}}}
public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);beanPostProcess.end();this.initMessageSource();this.initApplicationEventMulticaster();//Tomcat初始化this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var10) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);}this.destroyBeans();this.cancelRefresh(var10);throw var10;} finally {this.resetCommonCaches();contextRefresh.end();}}}
3、SpringBoot加载配置文件。
3.1、跟进run()到SpringApplication类的run()方法的ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
SpringApplication.run(TestApplication.class, args);
3.2、跟进prepareEnvironment()—>listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);—>SimpleApplicationEventMulticaster类的doInvokeListener()方法。
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {listener.onApplicationEvent(event);} catch (ClassCastException var6) {String msg = var6.getMessage();if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {throw var6;}Log logger = LogFactory.getLog(this.getClass());if (logger.isTraceEnabled()) {logger.trace("Non-matching event type for listener: " + listener, var6);}}}
当listener为EnvironmentPostProcessorApplicationListener的时候,进入onApplicationEvent()方法。
public void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationEnvironmentPreparedEvent) {this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);}if (event instanceof ApplicationPreparedEvent) {this.onApplicationPreparedEvent((ApplicationPreparedEvent)event);}if (event instanceof ApplicationFailedEvent) {this.onApplicationFailedEvent((ApplicationFailedEvent)event);}}
跟进onApplicationEnvironmentPreparedEvent()方法。
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {ConfigurableEnvironment environment = event.getEnvironment();SpringApplication application = event.getSpringApplication();Iterator var4 = this.getEnvironmentPostProcessors(event.getBootstrapContext()).iterator();while(var4.hasNext()) {EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var4.next();postProcessor.postProcessEnvironment(environment, application);}}
跟进到ConfigDataEnvironmentPostProcessor类的postProcessEnvironment()。
void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles) {try {this.logger.trace("Post-processing environment to add config data");ResourceLoader resourceLoader = resourceLoader != null ? resourceLoader : new DefaultResourceLoader();this.getConfigDataEnvironment(environment, (ResourceLoader)resourceLoader, additionalProfiles).processAndApply();} catch (UseLegacyConfigProcessingException var5) {this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]", var5.getConfigurationProperty()));this.postProcessUsingLegacyApplicationListener(environment, resourceLoader);}}
跟进processAndApply()方法。
void processAndApply() {ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers, this.loaders);this.bootstrapContext.register(Binder.class, InstanceSupplier.from(() -> {return this.contributors.getBinder((ConfigDataActivationContext)null, new ConfigDataEnvironmentContributors.BinderOption[]{BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE});}));ConfigDataEnvironmentContributors contributors = this.processInitial(this.contributors, importer);Binder initialBinder = contributors.getBinder((ConfigDataActivationContext)null, new ConfigDataEnvironmentContributors.BinderOption[]{BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE});this.bootstrapContext.register(Binder.class, InstanceSupplier.of(initialBinder));ConfigDataActivationContext activationContext = this.createActivationContext(initialBinder);contributors = this.processWithoutProfiles(contributors, importer, activationContext);activationContext = this.withProfiles(contributors, activationContext);contributors = this.processWithProfiles(contributors, importer, activationContext);this.applyToEnvironment(contributors, activationContext);}
跟进this.processInitial(this.contributors, importer)方法->withProcessedImports()方法->importer.resolveAndLoad(activationContext, locationResolverContext, loaderContext, imports)方法->this.load(loaderContext, resolved);
ConfigDataEnvironmentContributors withProcessedImports(ConfigDataImporter importer, ConfigDataActivationContext activationContext) {ConfigDataEnvironmentContributor.ImportPhase importPhase = ImportPhase.get(activationContext);this.logger.trace(LogMessage.format("Processing imports for phase %s. %s", importPhase, activationContext != null ? activationContext : "no activation context"));ConfigDataEnvironmentContributors result = this;int processed = 0;while(true) {ConfigDataEnvironmentContributor contributor = this.getNextToProcess(result, activationContext, importPhase);if (contributor == null) {this.logger.trace(LogMessage.format("Processed imports for of %d contributors", processed));return result;}if (contributor.getKind() == Kind.UNBOUND_IMPORT) {Iterable<ConfigurationPropertySource> sources = Collections.singleton(contributor.getConfigurationPropertySource());PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(result, activationContext, true);Binder binder = new Binder(sources, placeholdersResolver, (ConversionService)null, (Consumer)null, (BindHandler)null);ConfigDataEnvironmentContributor bound = contributor.withBoundProperties(binder);result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext, result.getRoot().withReplacement(contributor, bound));} else {ConfigDataLocationResolverContext locationResolverContext = new ContributorConfigDataLocationResolverContext(result, contributor, activationContext);ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);List<ConfigDataLocation> imports = contributor.getImports();this.logger.trace(LogMessage.format("Processing imports %s", imports));Map<ConfigDataResolutionResult, ConfigData> imported = importer.resolveAndLoad(activationContext, locationResolverContext, loaderContext, imports);this.logger.trace(LogMessage.of(() -> {return this.getImportedMessage(imported.keySet());}));ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase, this.asContributors(imported));result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext, result.getRoot().withReplacement(contributor, contributorAndChildren));++processed;}}}

到这里就差不多加载到配置文件了。
相关文章:
带着问题看SpringBoot
带着问题看SpringBoot 1、Spring容器具体是什么? 跟进run方法,context this.createApplicationContext(),得出容器是AnnotationConfigServletWebServerApplicationContext类。 SpringApplication.run(ServeroneApplication.class, args);…...
【Go 基础篇】Go语言匿名函数详解:灵活的函数表达式与闭包
介绍 在Go语言中,函数是一等公民,这意味着函数可以像其他类型的值一样被操作、传递和赋值。匿名函数是一种特殊的函数,它没有固定的函数名,可以在代码中被直接定义和使用。匿名函数在Go语言中具有重要的地位,它们常用…...
MobileNet、MobileNetV2和MobileNetV3创新点总结
当谈论MobileNet、MobileNetV2和MobileNetV3时,我们指的是一系列基于深度学习的轻量级神经网络架构,这些架构旨在在保持高度准确性的同时减少模型的计算和参数量。以下是它们各自的创新点的详细总结: MobileNet: 深度可分离卷积&…...
算法:数据转换处理2(云台显控)
#define DISPLAYFUNC #include"define.h" extern OS_EVENT *KEYMsg; uchar mBlank[21] = " " ; u c h a r s t r v g a [ ] = " 0.00 V "; uchar str_vga[] = "0.00V...
让大数据平台数据安全可见-行云管家
数字化经济在快速发展,大数据时代已经到来,大数据已经成为企业和政府决策的重要依据。然而大数据行业快速发展所带来的一系列安全问题也继续解决,例如数据安全更难保障,例如认证体系不完善等等。为此行云管家推出了大数据平台数据…...
微信小程序开发教学系列(3)- 页面设计与布局
3. 页面设计与布局 在微信小程序开发中,页面的设计和布局是非常重要的。一个好的页面设计可以提升用户体验,并使小程序更加吸引人。本章节将介绍如何设计和布局微信小程序的页面。 3.1 页面结构和样式的创建和设置 在创建微信小程序页面时,…...
基于JSP+Servlet+mysql员工权限管理系统
基于JSPServletmysql员工权限管理系统 一、系统介绍二、功能展示四、其他系统实现五、获取源码 一、系统介绍 项目类型:Java web项目 项目名称:基于JSPServlet的员工权限管理系统[qxxt] 项目架构:B/S架构 开发语言:Java语言 …...
Qt 自定义提示框 右下角冒泡
网页右下角上经常会出现一些提示性的信息,B/S有的东西,C/S当然也可以有,就像QQ的消息提示一样! 实现一个类似的东西并不困难,只要想明白原理实现起来就很简单了! 实现原理: (1&#…...
js、PHP连接外卖小票机打印机方案(调用佳博、芯烨等)
前言: 目前开发需要用到电脑直接连接外卖小票机打印小票,查阅各种资料,使用 6612345浏览器 终于解决了这个问题。 效果: PHP、js直接连接小票机并且自动出票。 支持的小票机: 目前测试可以的有:电脑A4打印…...
window定时备份MySQL数据库,默认备份7天,一小时备份一次
echo off setlocalrem 在Windows中添加任务计划以执行批处理脚本,请按照以下步骤操作:rem 打开Windows的“任务计划程序”应用程序。你可以通过按下Win R键,在运行对话框中输入taskschd.msc,然后按回车键来打开它。rem 在任务计划…...
正则中常见的流派及其特性
目前正则表达式主要有两大流派(Flavor):POSIX 流派与 PCRE 流派。 1、 POSIX 流派 POSIX 规范定义了正则表达式的两种标准: BRE 标准(Basic Regular Expression 基本正则表达式);ERE 标准&am…...
.net6.0引用的dll放置单独的文件夹
.net6.0 采用原有的设置方法不起作用 <?xml version"1.0" encoding"utf-8" ?> <configuration><startup> <supportedRuntime version"v4.0" sku".NETFramework,Versionv4.8" /></startup><runtim…...
CMake:检测外部库---自定义find模块
CMake:检测外部库---自定义find模块 导言项目结构CMakeLists.txt附录 导言 上一篇,我们了解了CMake其中一种自定义检测外部库的方式,本篇将展示通过编写一个find模块来定位系统上的ZeroMQ库,以便能够在非Unix操作系统上检测该库。 项目结构…...
vue直接使用高德api
第一步:在index.html 引入 <script src"https://webapi.amap.com/maps?v2.0&key你的key"></script>第二步:在你需要地图的时候 放入 <template><div style"width: 200px; height: 200px"><div id&q…...
Setting
目录 1 Setting 1.1.1 getChildList 1.1.2 getGroupList 1.1.3 setListener setOnChildClickListenermSettingList.setOnChildClickListener(new OnChildClickListener() {onChildClick...
时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元时间序列预测
时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元时间序列预测 目录 时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 时序预测 | Matlab实现SO-CNN-BiGRU蛇群算法优化…...
论文浅尝 | KRACL-利用图上下文和对比学习的稀疏KG补全
笔记整理:李娟,浙江大学博士,研究方向为知识图谱表示学习 论文链接:https://arxiv.org/pdf/2208.07622.pdf 代码链接:https://github.com/TamSiuhin/KRACL 介绍 知识图谱(KG)通常是不完整的&…...
【C++】右值引用,移动语义,完美转发
目录 右值引用移动语义拷贝构造与移动构造 万能引用与完美转发 右值引用 左值:可以出现在赋值符号的左边和右边,左值可以取地址。 右值:右值可以出现在赋值符号右边,不能出现在左边,右值不能取地址。 左值/右值引用就…...
【AI】即使AI 时代,程序员也无需焦虑
🚀欢迎来到本文🚀 🍉个人简介:陈童学哦,目前学习C/C、算法、Python、Java等方向,一个正在慢慢前行的普通人。 🏀系列专栏:陈童学的日记 💡其他专栏:CSTL&…...
Django实现DRF数据API接口格式封装
通常在进行前后端分离开发的时候,前端Vue调用后端接口都需要一个状态信息以及数据结合起来的数据。 如果是没有经过加工的API接口访问的数据一般是这样的。 [{"id": 1, "type": "1", "start": "2023-08-24", "end&qu…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
2025.6.9总结(利与弊)
凡事都有两面性。在大厂上班也不例外。今天找开发定位问题,从一个接口人不断溯源到另一个 接口人。有时候,不知道是谁的责任填。将工作内容分的很细,每个人负责其中的一小块。我清楚的意识到,自己就是个可以随时替换的螺丝钉&…...
