Spring Boot 启动流程源码分析(2)

前言:

前文我们宏观的分析了 Spring Boot 的启动流程,本篇将分析一下 SpringApplication#run 的重点步骤。

Spring Boot 系列文章传送门

Spring Boot 启动流程源码分析(2)

SpringApplication#run 方法源码解析

解析 SpringApplication#run 方法源码,Spring Boot 启动流程大概分为一下几点步骤,如下:

  • 获取监听器,启动监听。
  • 加载环境配置。
  • 创建应用程序上下文。
  • 准备上下文,各种初始化操作。
  • 刷新上下文,最终调用到 AbstractApplicationContext#refresh 方法,也就是 Spirng 容器启动。
  • 刷新后操作,模板方法,空实现。
//org.springframework.boot.SpringApplication#run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {//计时器 记录启动耗时StopWatch stopWatch = new StopWatch();//启动开始stopWatch.start();//创建默认的引导上下文DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();//可配置的应用程序上下文ConfigurableApplicationContext context = null;//java.awt.headless 是 J2SE 的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置 很多监控工具如jconsole 需要将该值设置为true 系统变量默认为truethis.configureHeadlessProperty();//获取 SpringApplicationRunListener 实例数组 默认获取的是 EventPublishRunListenerSpringApplicationRunListeners listeners = this.getRunListeners(args);//启动监听listeners.starting(bootstrapContext, this.mainApplicationClass);try {//创建 ApplicationArguments 默认应用程序参数 对象ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//加载环境配置ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);//忽略配置 bena 信息this.configureIgnoreBeanInfo(environment);//Banner 打印Banner printedBanner = this.printBanner(environment);//创建 应用程序上下文context = this.createApplicationContext();//设置应用程序启动context.setApplicationStartup(this.applicationStartup);//准备上下文 就是各种初始化错误this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);//刷新上下文 最终调用到 AbstractApplicationContext#refresh 方法this.refreshContext(context);//刷新后操作 空实现this.afterRefresh(context, applicationArguments);//结束计时stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}//监听器启动listeners.started(context);//调用 ApplicationRunner 和 CommandLineRunner this.callRunners(context, applicationArguments);} catch (Throwable var10) {//失败处理this.handleRunFailure(context, var10, listeners);throw new IllegalStateException(var10);}try {//通知监听器  Spring Boot 正在运行listeners.running(context);return context;} catch (Throwable var9) {//失败处理this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);throw new IllegalStateException(var9);}
}

获取监听器

SpringApplication#getRunListeners 方法获取监听器,启动监听,SpringApplicationRunListeners 类中有一个监听器数组 listeners,获取监听器的源码前文在分析 SpringApplication 构造函数的时候已经分析过了,就是加载 class 下 META-INF/spring.factories 文件中 ApplicationListener 的实现类。

//org.springframework.boot.SpringApplication#getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class[]{SpringApplication.class, String[].class};//创建一个 SpringApplicationRunListeners 对象 加载 class 下 META-INF/spring.factories 文件中 ApplicationListener 的实现类return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}//org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {//真正处理的方法return this.getSpringFactoriesInstances(type, new Class[0]);
}//org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {//获取类加载器ClassLoader classLoader = this.getClassLoader();//获取所有类名 SpringFactoriesLoader.loadFactoryNames(type, classLoader) 重点关注一下//SpringFactoriesLoader.loadFactoryNames(type, classLoader) 就是根据接口名字 获取实现类的名称Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));//根据获取到的所有类名获取实例对象List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);//排序AnnotationAwareOrderComparator.sort(instances);return instances;
}

启动监听器

SpringApplicationRunListeners#starting 启动监听器,其调用的是 EventPublishingRunListener#starting 方法,最终调用的是 SimpleApplicationEventMulticaster#multicastEvent 方法来发布监听事件。

//org.springframework.boot.SpringApplicationRunListeners#starting
void starting() {//迭代遍历所有监听器Iterator var1 = this.listeners.iterator();while(var1.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();//调用 事件发布运行监听器 EventPublishingRunListener#starting 方法listener.starting();}}//org.springframework.boot.context.event.EventPublishingRunListener#starting
public void starting() {//调用 简单应用程序事件多播器 SimpleApplicationEventMulticaster#multicastEvent 多播事件 也就是启动监听事件this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent)
public void multicastEvent(ApplicationEvent event) {//调用 简单应用程序事件多播器 SimpleApplicationEventMulticaster#multicastEventthis.multicastEvent(event, this.resolveDefaultEventType(event));
}//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {//解析事件类型ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);//获取线程池Executor executor = this.getTaskExecutor();//迭代遍历监听器Iterator var5 = this.getApplicationListeners(event, type).iterator();while(var5.hasNext()) {//监听器ApplicationListener<?> listener = (ApplicationListener)var5.next();if (executor != null) {//线程池异步发送监听事件executor.execute(() -> {this.invokeListener(listener, event);});} else {//同步发送监听事件this.invokeListener(listener, event);}}}

加载环境配置

SpringApplication#prepareEnvironment 方法就是获取一个环境对象,Environment 接口提供了三种实现,标准环境 StandardEnvironment、web 应用环境 StandardServletEnvironment、响应式 web 应用环境 StandardReactiveWebEnvironment。

//org.springframework.boot.SpringApplication#prepareEnvironment 
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {//获取或创建 配置环境对象ConfigurableEnvironment environment = this.getOrCreateEnvironment();//配置环境this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach((Environment)environment);//发布环境已准备事件listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);this.configureAdditionalProfiles((ConfigurableEnvironment)environment);//环境配置绑定到 Spring 应用程序上this.bindToSpringApplication((ConfigurableEnvironment)environment);//是否是自定义环境if (!this.isCustomEnvironment) {environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());}ConfigurationPropertySources.attach((Environment)environment);//返回环境配置对象return (ConfigurableEnvironment)environment;
}//org.springframework.boot.SpringApplication#getOrCreateEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {//环境为空判断if (this.environment != null) {//不为空 直接返回return this.environment;} else {//为空 根据项目类型创建不同的环境对象switch(this.webApplicationType) {case SERVLET://响应式 web 应用环境return new StandardServletEnvironment();case REACTIVE://web 应用环境return new StandardReactiveWebEnvironment();default://标准环境return new StandardEnvironment();}}
}

创建应用程序上下文

创建容器会调用 ApplicationContextFactory#create 方法,根据项目类型去创建容器,项目类型前文已经多次赘述,这里不再分析了。

protected ConfigurableApplicationContext createApplicationContext() {return this.applicationContextFactory.create(this.webApplicationType);
}package org.springframework.boot;import java.util.function.Supplier;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;@FunctionalInterface
public interface ApplicationContextFactory {ApplicationContextFactory DEFAULT = (webApplicationType) -> {try {switch(webApplicationType) {case SERVLET:return new AnnotationConfigServletWebServerApplicationContext();case REACTIVE:return new AnnotationConfigReactiveWebServerApplicationContext();default:return new AnnotationConfigApplicationContext();}} catch (Exception var2) {throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);}};ConfigurableApplicationContext create(WebApplicationType webApplicationType);static ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {return of(() -> {return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);});}static ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {return (webApplicationType) -> {return (ConfigurableApplicationContext)supplier.get();};}
}

准备上下文,完成各种初始化操作

SpringApplication#prepareContext 方法主要是做一些容器刷新之前的动作,完成各类初始化动作,其中有一个比较核心的操作,把启动类注入容器,为后续开启自动化配置奠定了基础。

//org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {//设置上下文环境context.setEnvironment(environment);//执行上下文后处理this.postProcessApplicationContext(context);//执行 ApplicationContextInitializerthis.applyInitializers(context);//发布上下文准备好的监听事件listeners.contextPrepared(context);//关闭引导上下文bootstrapContext.close(context);if (this.logStartupInfo) {this.logStartupInfo(context.getParent() == null);this.logStartupProfileInfo(context);}//获取 ApplicationContextInitializer ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();//注册单例bean springApplicationArguments  容器指定的参数封装成 bean  注入容器beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {//将 Banner 封装成 bean 注入到容器中beanFactory.registerSingleton("springBootBanner", printedBanner);}//是否是 DefaultListableBeanFactory 类型的容器if (beanFactory instanceof DefaultListableBeanFactory) {//是 强行覆盖((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}//是否懒加载if (this.lazyInitialization) {//加 懒加载 beanFactory 处理器context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}//获取启动类指定的参数Set<Object> sources = this.getAllSources();Assert.notEmpty(sources, "Sources must not be empty");//加载启动类 将启动类注入容器this.load(context, sources.toArray(new Object[0]));//发布容器加载完成事件listeners.contextLoaded(context);
}

刷新上下文

刷新上下文,最终调用到 AbstractApplicationContext#refresh 方法,也就是 Spirng 容器启动的核心方法。

AbstractApplicationContext#refresh 方法传送门:

深入理解 Spring IOC 底层实现机制(refresh 方法源码分析)

//org.springframework.boot.SpringApplication#refreshContext
private void refreshContext(ConfigurableApplicationContext context) {//判斷是否注册关闭钩子函数 默认注册if (this.registerShutdownHook) {try {//注册关闭钩子函数context.registerShutdownHook();} catch (AccessControlException var3) {}}//继续调用 refresh 方法this.refresh((ApplicationContext)context);
}//org.springframework.boot.SpringApplication#refresh(org.springframework.context.ApplicationContext)
@Deprecated
protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);//继续调用 refresh 方法this.refresh((ConfigurableApplicationContext)applicationContext);
}//org.springframework.boot.SpringApplication#refresh(org.springframework.context.ConfigurableApplicationContext)
protected void refresh(ConfigurableApplicationContext applicationContext) {//调用 AbstractApplicationContext#refresh 方法applicationContext.refresh();
}//org.springframework.context.support.AbstractApplicationContext#refresh
//IOC 核心方法
public void refresh() throws BeansException, IllegalStateException {//防止 启动和销毁并发执行synchronized(this.startupShutdownMonitor) {//启动步骤记录StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");//刷新准备工作this.prepareRefresh();//创建 beanFactory 将配置文件解析为 beandefiniton 对象 注册到 beanFactory 中//ConfigurableListableBeanFactory是一个接口 真正干活的是 DefaultListableBeanFactoryConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//beanFactory 预处理 主要是设置 beanFactory 类加载器及忽略一些自动装配 设置一些默认benathis.prepareBeanFactory(beanFactory);try {//beanFactory 后置处理 准备完成后需要做的事情 默认是空实现 是一个扩展点 可以子类去实现this.postProcessBeanFactory(beanFactory);//启动 bean post-process 步骤记录StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");//回调 beanFactory 后置处理器 beanFactoryPostProcessors 的 postProcessorsBeanFactory 方法   (也可以说是激活 beanFactoryPostPorcess)this.invokeBeanFactoryPostProcessors(beanFactory);//注册beanPostProcessors bean 后置处理器(注意上面是beanFactory后置处理器) 在bean 初始化之前之后执行this.registerBeanPostProcessors(beanFactory);//bean 后置处理器步骤结束beanPostProcess.end();//初始化国际化资源this.initMessageSource();//初始化应用程序事件多播器this.initApplicationEventMulticaster();//默认是空方法 可以子类重写  自己进行扩展this.onRefresh();//注册监听器this.registerListeners();//初始化单例bean(非懒加载)this.finishBeanFactoryInitialization(beanFactory);//完成后刷新 包括清空资源 发布事件等this.finishRefresh();} catch (BeansException var10) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);}//销毁benthis.destroyBeans();//取消刷新this.cancelRefresh(var10);throw var10;} finally {this.resetCommonCaches();contextRefresh.end();}}
}

刷新后操作

SpringApplication#afterRefresh 方法是个模板方法,默认空实现,可以自己去扩展。

//org.springframework.boot.SpringApplication#afterRefresh
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {}

SpringApplication#callRunners 方法分析

SpringApplication#callRunners 调用 ApplicationRunner 和 CommandLineRunner 的实现类,也就是平时我们自定义一些实现了 Runner 接口的类,在项目启动时候执行。

//org.springframework.boot.SpringApplication#callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) {//存储所有的 RunnerList<Object> runners = new ArrayList();//获取所有的 ApplicationRunner 的实现类 加入到 runners 中runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());//获取所有的 CommandLineRunner 的实现类 加入到 runners 中runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());//对所有 Runner 排序AnnotationAwareOrderComparator.sort(runners);//迭代遍历Iterator var4 = (new LinkedHashSet(runners)).iterator();while(var4.hasNext()) {Object runner = var4.next();//ApplicationRunner 类型 runnerif (runner instanceof ApplicationRunner) {//调用 runner 的 run 方法this.callRunner((ApplicationRunner)runner, args);}//CommandLineRunner 类型 runnerif (runner instanceof CommandLineRunner) {//调用 runner 的 run 方法this.callRunner((CommandLineRunner)runner, args);}}}//org.springframework.boot.SpringApplication#callRunner(org.springframework.boot.CommandLineRunner, org.springframework.boot.ApplicationArguments)
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {try {//执行 runner 的 run 方法 也就是我们自己定义的 runner 的业务方法runner.run(args.getSourceArgs());} catch (Exception var4) {throw new IllegalStateException("Failed to execute CommandLineRunner", var4);}
}

至此,Spring Boot 的启动流程分析完毕,希望可以帮助到有需要的小伙伴。

如有不正确的地方请各位指出纠正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/863119.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Milvus【部署 01】向量数据库Milvus在Linux环境下的在线+离线安装

向量数据库Milvus在Linux环境下的在线离线安装 1.千问简介2.在线安装2.离线安装 1.千问简介 Milvus 是一款专为处理高维向量数据设计的开源云原生数据库&#xff0c;旨在满足海量向量数据的实时召回需求。它由 Zilliz 公司开发并维护&#xff0c;基于Apache许可证2.0版本发布。…

uboot Device tree error at node ‘__symbols__‘

宏定义相关 是设备树有问题&#xff0c;比如没包含宏定义所在的头文件&#xff1a; &i2c2 {status "okay";pinctrl-0 <&i2c2_pb0_pins>;pinctrl-names "default";touchscreen48 {reg <0x48>;compatible "ti,tsc2007"…

【JavaScript脚本宇宙】精通前端开发:六大热门CSS框架详解

前端开发的利器&#xff1a;深入了解六大CSS框架 前言 在现代Web开发中&#xff0c;选择适合的前端框架和工具包是构建高效、响应式和美观的网站或应用程序的关键。本文将详细介绍六个广受欢迎的CSS框架&#xff1a;Bootstrap、Bulma、Tailwind CSS、Foundation、Materialize…

ASUS华硕A豆14笔记本电脑I421EAYB,I421EQYB_ADOL14EA工厂模式原厂Win11系统安装包下载

适用型号&#xff1a;ADOL14EA笔记本I421EAYB、I421EQYB 链接&#xff1a;https://pan.baidu.com/s/1krU8m_lbApyUfZQo5E4cCQ?pwd0ewl 提取码&#xff1a;0ewl 华硕原装WIN11系统工厂安装包&#xff0c;带有MyASUS WinRE RECOVERY恢复功能、自带所有驱动、出厂主题壁纸、系…

Linux上安装JDK,Java起飞,开启编程之旅

在Linux环境下搭建Java开发平台&#xff0c;是许多开发者入门Java世界的第一步。Java的跨平台特性使得在Linux上安装JDK尤为重要&#xff0c;它不仅能为Linux开发者提供更广阔的应用场景&#xff0c;也是探索Java强大功能的起点。 接下来&#xff0c;让我们一起在Linux中完成J…

【SpringMVC】_SpringMVC实现留言墙

目录 1. 需求分析 2. 接口定义 2.1 提交留言 2.2 获取全部留言 3. 响应数据 4. 服务器代码 4.1 MessageInfo 文件 4.2 MessageController 文件 5. 前端页面代码 5. 运行测试 1. 需求分析 实现如下页面&#xff1a; 1、输入留言信息&#xff0c;点击提交后&#xff0…

使用腾讯云服务器从0搭建个人网站,超简单图文教程

使用腾讯云服务器搭建网站全流程&#xff0c;包括轻量应用服务器和云服务器CVM建站教程&#xff0c;轻量可以使用应用镜像一键建站&#xff0c;云服务器CVM可以通过安装宝塔面板的方式来搭建网站&#xff0c;腾讯云服务器网txyfwq.com整理使用腾讯云服务器建站教程&#xff0c;…

NPOI入门指南:轻松操作Excel文件的.NET库

目录 引言 一、NPOI概述 二、NPOI的主要用途 三、安装NPOI库 四、NPOI基本使用 六、性能优化和内存管理 七、常见问题与解决方案 八、结论 附录 引言 Excel文件作为数据处理的重要工具&#xff0c;广泛应用于各种场景。然而&#xff0c;在没有安装Microsoft Office的…

llama.cpp

https://github.com/echonoshy/cgft-llm 【大模型量化】- Llama.cpp轻量化模型部署及量化_哔哩哔哩_bilibili github.com/ggerganov/llama.cpp cd ~/code/llama.cpp/build_cuda/bin ./quantize --allow-requantize /root/autodl-tmp/models/Llama3-8B-Chinese-Chat-GGUF/Llama…

海尔智家:科技优秀是一种习惯

海尔智家&#xff1a;科技优秀是一种习惯 2024-06-28 15:19代锡海 6月24日&#xff0c;2023年度国家科学技术奖正式揭晓。海尔智家“温湿氧磁多维精准控制家用保鲜电器技术创新与产业化”项目荣获国家科学技术进步奖&#xff0c;成为家电行业唯一牵头获奖企业。 很多人说&…

前端Axios失败重试

前端Axios失败重试 失败重试次数写在vite全局配置中&#xff0c;之后统一修改即可 vite环境变量 # 失败重试次数 VITE_BASE_API_RETRY5# 失败重试时间 VITE_BASE_API_RETRY_DELAY3000Axios重试 思路 在Axios创建中读取vite环境变量配置&#xff0c;将其赋值在发送请求时&a…

Obsidan插件开发

1 Obidian 开发 Obsidian 基于 Electron 框架开发&#xff0c;其前端主要使用了 HTML、CSS 和 JavaScript&#xff0c;而后端使用了 Node.js。Node.js 是基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;使 JavaScript 能在服务器端运行。 在开发 Obsidian 插件时&…

qt 用宏控制静态接口的统一

1.概要 /** * 单件宏实验 * 创建一个可以生成单件的宏 * 起因&#xff1a;想让有些控件单件&#xff0c;但是c不支持静态的继承&#xff08;c#支持&#xff09; * 那么如果保证这些接口的统一呢&#xff0c;用宏 */ 2.代码 2.1 a.h #ifndef A_H #define A_H#include &…

分布式kettle调度管理平台简介

介绍 Kettle&#xff08;也称为Pentaho Data Integration&#xff09;是一款开源的ETL&#xff08;Extract, Transform, Load&#xff09;工具&#xff0c;由Pentaho&#xff08;现为Hitachi Vantara&#xff09;开发和维护。它提供了一套强大的数据集成和转换功能&#xff0c…

【C++】类、静态、枚举、重载、多态、继承、重写、虚函数

五、类 面向对象编程是一个巨大的编程范式。C中的类class就是基于对象的程序设计。 我们可以用类来定义一个新的类型&#xff0c;这些新类型就可以像内置类型一样使用。 内置类型颗粒度太太小&#xff0c;现实需求又非常复杂&#xff0c;这就需要我们把内置类型适度的进行拼搭…

源码学习:文件描述符

在进程描述学习中&#xff0c;扯到了max_fds&#xff0c;接着就联想到了日常运维中常见的ulimit参数、sysctl内核参数&#xff0c;原来以为max_fds与这些个关联性比较强&#xff0c;但经过一早上折腾以后&#xff0c;发现其实还是有一些差距的。但是在学习过程中&#xff0c;却…

【C++】数组、字符串

六、数组、字符串 讨论数组离不开指针&#xff0c;指针基本上就是数组的一切的基础&#xff0c;数组和指针的相关内容参考我的C系列博文&#xff1a;【C语言学习笔记】四、指针_通过变量名访问内存单元中的数据缺点-CSDN博客【C语言学习笔记】三、数组-CSDN博客 1、数组就是&…

RxJava快速入门

简单来说RxJava是一个实现响应式编程的类库。 那什么是响应式编程&#xff1f; 响应式编程的核心思想是"数据流是第一等公民”&#xff0c;程序的逻辑建立在数据流的变化之上。 响应式编程的几个核心概念: &#xff08;1&#xff09;数据流&#xff1a;在响应式编程中&…

数据结构03 链表的基本操作【C++数组模拟实现】

前言&#xff1a;本节内容主要了解链表的基本概念及特点&#xff0c;以及能够通过数组模拟学会链表的几种基本操作&#xff0c;下一节我们将通过STL模板完成链表操作&#xff0c;可以通过专栏进入查看下一节哦~ 目录 单链表及其特点 完整链表构成 完整链表简述 创建单链表 …

京东云备案流程图_云主机快速ICP备案_京东云服务器备案问题解答

京东云ICP备案流程&#xff0c;备案包括网站和APP备案&#xff0c;以及备案问题解答FAQ&#xff0c;阿腾云以京东云网站域名备案流程为例&#xff0c;先填写主办单位信息&#xff0c;选择网站备案或APP备案&#xff0c;申请授权码并验证&#xff0c;填写并上传主办单位详细信息…