一个spring boot项目的启动过程分析

1、web.xml 定义入口类

<context-param><param-name>contextConfigLocation</param-name><param-value>com.baosight.ApplicationBoot</param-value>
</context-param>

2、主入口类: ApplicationBoot,SpringBoot项目的mian函数


@SpringBootApplication(scanBasePackages = "com.bs")
@ServletComponentScan("com.bs.4j.core.web.servlet")
@ImportResource(locations = {"classpath*:spring/framework/platApplicationContext*.xml", "classpath*:spring/framework/applicationContext*.xml"})
@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class})
public class ApplicationBoot extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication app = new SpringApplication(ApplicationBoot.class);app.run(args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(ApplicationBoot.class);}}

3、SpringApplication

SpringApplication类是Spring Boot框架的核心组件之一,它负责整个应用的启动和初始化过程。SpringApplication的设计目标是简化Spring应用的启动步骤,提供一套开箱即用的配置,让开发者能够快速启动和运行Spring应用。

在这个类中:

3.1、SpringApplication构造方法

/*** Create a new {@link SpringApplication} instance. The application context will load* beans from the specified primary sources (see {@link SpringApplication class-level}* documentation for details. The instance can be customized before calling* {@link #run(String...)}.* @param primarySources the primary bean sources* @see #run(Class, String[])* @see #SpringApplication(ResourceLoader, Class...)* @see #setSources(Set)*/public SpringApplication(Class<?>... primarySources) {this(null, primarySources);}/*** Create a new {@link SpringApplication} instance. The application context will load* beans from the specified primary sources (see {@link SpringApplication class-level}* documentation for details. The instance can be customized before calling* {@link #run(String...)}.* @param resourceLoader the resource loader to use* @param primarySources the primary bean sources* @see #run(Class, String[])* @see #setSources(Set)*/@SuppressWarnings({ "unchecked", "rawtypes" })public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}

 对于构造函数的解读

  1. 参数初始化

    • resourceLoader:这是一个资源加载器,用于从类路径或其他位置加载资源,如配置文件、静态资源等。
    • primarySources:这是应用程序的主要配置源,通常是一个或多个配置类的数组,用于引导Spring的自动配置和组件扫描。
  2. 非空检查

    • primarySources进行非空检查,确保至少有一个配置源被提供,否则将抛出IllegalArgumentException
  3. 配置源存储

    • primarySources转换为LinkedHashSet集合并存储,保持插入顺序,这有助于后续的配置解析和组件扫描。
  4. Web应用类型推断

    • 调用WebApplicationType.deduceFromClasspath()方法自动检测应用的Web类型,是Servlet-based、Reactive-based还是None(非Web应用)。这一决策影响了Spring Boot如何初始化Web环境。
  5. ApplicationContext Initializers设置

    • 调用getSpringFactoriesInstances方法来获取所有实现了ApplicationContextInitializer接口的实例,并将其设置为SpringApplication的initializers。这些initializers会在ApplicationContext创建过程中被调用,用于自定义上下文的初始化。
  6. Application Listeners设置

    • 同样地,通过getSpringFactoriesInstances方法获取所有实现了ApplicationListener接口的实例,并将其设置为SpringApplication的listeners。这些listeners会在应用生命周期的不同阶段被触发,如启动、停止等。
  7. 主应用类推断

    • 调用deduceMainApplicationClass方法来确定应用的主类,通常是启动应用的那个类,用于在某些情况下(如生成文档)标识应用本身。

 3.1.1、WebApplicationType.deduceFromClasspath()

检测应用的Web类型,在下文ConfigurableApplicationContext的实例化中会使用到

 3.1.2、setInitializers

初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, new Class<?>[] {});}private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}

1、getSpringFactoriesInstances有什么用,做了什么,这个方法是根据给定的类型typeClassLoader,从spring-core提供的FACTORIES_RESOURCE_LOCATION=META-INF/spring.factories文件中加载所有该类型的工厂类名,即获取指定的类(key)的同一入口方法。这里使用了LinkedHashSet来存储这些名字,确保它们是唯一的且按插入顺序排序。这一块在SpringFactoriesLoader.loadFactoryNames/loadSpringFactories中实现

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {String factoryClassName = factoryClass.getName();return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryClassName = ((String) entry.getKey()).trim();for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryClassName, factoryName.trim());}}}cache.put(classLoader, result);return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}}

在这里,获取的是key为 org.springframework.context.ApplicationContextInitializer 的类。ApplicationContextInitializer 是Spring框架的类, 这个类的主要目的就是在   ConfigurableApplicationContext 调用refresh()方法之前,回调这个类的initialize方法。通过  ConfigurableApplicationContext 的实例获取容器的环境Environment,从而实现对配置文件的修改完善等工作。

 

3.1.3 、setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

 ApplicationListener 的加载过程和上面的 ApplicationContextInitializer 类的加载过程是一样的.ApplicationListener 是spring的事件监听器,典型的观察者模式,通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现对spring容器全生命周期的监听

SpringApplication 类的实例化过程,我们可以在spring容器创建之前做一些预备工作,和定制化的需求。比如,自定义SpringBoot的Banner,比如自定义事件监听器,再比如在容器refresh之前通过自定义 ApplicationContextInitializer 修改配置一些配置或者获取指定的bean都是可以的

3.2、SpringApplication.run() 

如下面代码所示

/*** Run the Spring application, creating and refreshing a new* {@link ApplicationContext}.* @param args the application arguments (usually passed from a Java main method)* @return a running {@link ApplicationContext}*/
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);prepareContext(context, environment, listeners, applicationArguments,printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;
}

run方法详解:

  • 计时和异常处理设置

    • 创建一个StopWatch对象来测量应用启动所需的时间。

    • 初始化一个空列表exceptionReporters,用于存放异常报告器。

  • 配置无头模式

    • 调用configureHeadlessProperty方法确保应用在没有图形界面的环境中也能运行。

  • 监听器初始化

    • 获取SpringApplicationRunListeners监听器实例,并调用starting方法通知监听器应用即将开始启动。

  • 解析命令行参数

    • 创建ApplicationArguments实例,用于解析传入的命令行参数。

  • 环境准备

    • 准备ConfigurableEnvironment环境,这个环境包含了应用的配置信息。应用上下文环境包括什么呢?包括计算机的环境,Java环境,Spring的运行环境,Spring项目的配置(在SpringBoot中就是那个熟悉的application.properties/yml)等等。

  • 忽略Bean信息配置

    • 调用configureIgnoreBeanInfo方法,这通常用于性能优化,避免加载不必要的Bean信息。

  • 打印Banner

    • 打印应用的启动Banner,显示应用名、版本等信息。

  • 创建ApplicationContext

    • 创建ConfigurableApplicationContext上下文,这是Spring管理Bean的容器。

  • 异常报告器获取

    • 通过getSpringFactoriesInstances方法获取所有SpringBootExceptionReporter实例。

  • 上下文准备

    • 调用prepareContext方法进行上下文的准备工作,包括注册Bean后处理器、监听器等。

  • 刷新上下文

    • 调用refreshContext方法刷新上下文,这是Spring Bean生命周期的关键点。

  • 启动后操作

    • 调用afterRefresh方法执行一些应用启动后的操作,如初始化定时任务等。

  • 日志记录

    • 如果配置了记录启动信息,使用StartupInfoLogger记录应用启动完成的日志。

  • 监听器回调

    • 通知监听器应用已经启动。

  • 运行Runners

    • 调用callRunners方法执行定义好的ApplicationRunnerCommandLineRunner,它们通常用于执行一些启动后的初始化工作。

  • 异常处理

    • 在整个启动过程中捕获并处理可能发生的异常,确保应用能够优雅地处理错误。

  • 返回ApplicationContext

    • 最终返回创建的ConfigurableApplicationContext实例,这是Spring Boot应用的核心组件。

3.3、ConfigurableApplicationContext

ConfigurableApplicationContext是Spring框架中ApplicationContext接口的一个扩展,它提供了更多的配置和控制能力,是Spring应用程序上下文的高级接口。在Spring Boot中,ConfigurableApplicationContext扮演着核心角色,用于管理应用程序的生命周期和Bean的配置。下面是一些关键特性及其作用的详细解读:

 配置和定制

ConfigurableApplicationContext允许开发者在应用程序启动时对上下文进行更深入的定制,例如设置EnvironmentResourceLoaderMessageSourceApplicationEventPublisher等。这使得你可以更灵活地调整Spring容器的行为,以适应不同的应用场景。

 刷新上下文

ApplicationContext不同的是,ConfigurableApplicationContext提供了refresh()方法,用于手动刷新上下文,重新加载配置并初始化Bean。这是非常有用的,特别是在测试场景中,你需要在每次测试之前重置Spring上下文的状态。

关闭上下文

ConfigurableApplicationContext提供了close()方法,允许你优雅地关闭上下文,释放资源。这对于那些不需要一直运行的应用程序尤其重要,比如批处理作业或命令行应用。

监听器支持

它支持ApplicationListener,允许你在上下文的生命周期事件(如启动、关闭、Bean实例化等)中注册监听器,以便于执行自定义逻辑。这对于集成日志记录、健康检查等功能非常有用。

环境感知

ConfigurableApplicationContext允许你访问和修改应用的Environment,这包括读取和设置配置属性、切换不同的配置文件(profiles)等。这对于多环境部署(如开发、测试、生产)的管理至关重要。

事件发布

除了标准的ApplicationEventPublisher功能,ConfigurableApplicationContext还提供了更细粒度的事件发布和监听机制,这对于实现复杂的业务逻辑和系统集成非常有帮助。

实例化

在Spring Boot中,SpringApplicationrun方法通过createApplicationContext返回一个ConfigurableApplicationContext实例,这通常是应用程序的主要入口点,可以通过这个上下文访问到所有由Spring管理的Bean和资源。下面则是createApplicationContext的具体实现:

Strategy method used to create the ApplicationContext. By default this method will respect any explicitly set application context or application context class before falling back to a suitable default.
返回值:
the application context (not yet refreshed)
请参阅:
setApplicationContextClass(Class)
protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;case REACTIVE:contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default:contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);}}catch (ClassNotFoundException ex) {throw new IllegalStateException("Unable create a default ApplicationContext, "+ "please specify an ApplicationContextClass",ex);}}return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}

3.2.1、WebApplicationType详解 

WebApplicationType,一个枚举,且里面定义了三个枚举值,分别是 NONE、SERVLET、REACTIVE

SERVLET:传统的Servlet-based web应用,内嵌基于 servlet 的 web 服务器(如:Tomcat,Jetty,Undertow 等,其实现在大多Java网站应用都是采用的基于 Tomcat 的 servlet 类型服务器),默认使用AnnotationConfigServletWebServerApplicationContext作为上下文。

REACTIVE:响应式web应用,在 servlet 容器当中,采用命令式编程方式,代码一句一句的执行,这样更有利于理解与调试,而在反应式的 web 编程中,是基于异步响应式,现在 WebFlux 框架就是一个较为流行的反应式编程,默认使用AnnotationConfigReactiveWebServerApplicationContext作为上下文。

NONE:既不是SERVLET也不是REACTIVE:即非Web应用,非 web 应用程序(不内嵌服务器),则默认使用AnnotationConfigApplicationContext作为上下文。

而关于Springboot 如何确定程序的应用类型 WebApplicationType 的?

在SpringApplication构造方法:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}

this.webApplicationType = WebApplicationType.deduceFromClasspath();其中 WebApplicationType.deduceFromClasspath() 这个方法实现如下

	static WebApplicationType deduceFromClasspath() {if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {return WebApplicationType.REACTIVE;}for (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}return WebApplicationType.SERVLET;}

ClassUtils.isPresent()?干什么的?用来判断一个类的存在性的,当这个类存在,那么返回的就是 true;当这个类不存在时,返回的结果就是 fasle。

(1)WEBFLUX_INDICATOR_CLASS,WEBMVC_INDICATOR_CLASS,JERSEY_INDICATOR_CLASS常量值又分别是什么?看源码

private static final String WEBMVC_INDICATOR_CLASS = "org.springframework."+ "web.servlet.DispatcherServlet";private static final String WEBFLUX_INDICATOR_CLASS = "org."+ "springframework.web.reactive.DispatcherHandler";private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

当项目中存在 DispatcherHandler 这个类,且不存在 DispatcherServlet 类和ServletContainer时,程序的应用类型就是 REACTIVE,也就是他会加载嵌入一个反应式的 web 服务器。

(2)而SERVLET_INDICATOR_CLASSES

private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };

当项目中 Servlet 和 ConfigurableWebApplicationContext 其中一个不存在时,则程序的应用类型为 NONE,它并不会加载内嵌任何 web 服务器。

(3)除了上面两种情况外,其余的都按 SERVLET 类型处理,会内嵌一个 servlet 类型的 web 服务器

上面的这些类的判定,都来源于 Spring 的相关依赖包,而这依赖包是否需要导入,也是开发者所决定的,所以说开发者可以决定程序的应用类型,并不是 Srpingboot 本身决定的。

 3.4、refreshContext

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

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

相关文章

(三)Redis持久化,你真的懂了吗?万字分析AOF和RDB的优劣 AOF的刷盘、重写策略 什么叫混合重写 MP-AOF方案是什么

引言 —— Redis基础概念 Redis概念&#xff1a;Redis (REmote DIctionary Server) 是用 C 语言开发的一个开源的高性能键值对&#xff08;key-value&#xff09;数据库。 为什么会出现Redis呢&#xff1f;它的到来是为了解决什么样的问题&#xff1f; Redis 是一个NOSQL类型…

操作系统真象还原:创建文件系统

14.2 创建文件系统 14.2.1 创建超级块、i结点、目录项 超级块 /** Author: Adward-DYX 1654783946qq.com* Date: 2024-05-07 10:18:02* LastEditors: Adward-DYX 1654783946qq.com* LastEditTime: 2024-05-07 11:24:50* FilePath: /OS/chapter14/14.2/fs/super_block.h* Des…

WPF学习(6) -- WPF命令和通知

一 、WPF命令 1.ICommand代码 创建一个文件夹和文件 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input;namespace 学习.Command {public class MyCommand : ICommand{Acti…

CCSI: 数据无关类别增量学习的持续类特定印象| 文献速递-基于深度学习的多模态数据分析与生存分析

Title 题目 CCSI: Continual Class-Specific Impression for data-free class incremental learning CCSI: 数据无关类别增量学习的持续类特定印象 01 文献速递介绍 当前用于医学影像分类任务的深度学习模型表现出令人鼓舞的性能。这些模型大多数需要在训练之前收集所有的…

中间件——Kafka

两个系统各自都有各自要去做的事&#xff0c;所以只能将消息放到一个中间平台&#xff08;中间件&#xff09; Kafka 分布式流媒体平台 程序发消息&#xff0c;程序接收消息 Producer&#xff1a;Producer即生产者&#xff0c;消息的产生者&#xff0c;是消息的入口。 Brok…

[Vulnhub] Sedna BuilderEngine-CMS+Kernel权限提升

信息收集 IP AddressOpening Ports192.168.8.104TCP:22, 53, 80, 110, 111, 139, 143, 445, 993, 995, 8080, 55679 $ nmap -p- 192.168.8.104 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2 …

在RHEL9.4上启用SFTP服务

FTP存在的不足&#xff1a; 明文传输 FTP传输的数据&#xff08;包括用户名、密码和文件内容&#xff09;都是明文的&#xff0c;这意味着数据可以被网络上的任何人截获并读取。没有内置的加密机制&#xff0c;容易受到中间人攻击。 被动模式下的端口问题 FTP的被动模式需要…

读人工智能全传12人工智能导致的问题1

1. 人工智能会导致什么问题 1.1. 人工智能是一门通用技术&#xff1a;它的应用仅仅受限于我们的想象 1.1.1. 所有的技术都可能产生意想不到的效果&#xff0c;未来几十年甚至几百年内都存在可能性 1.2. 所有的技术都可能被滥用 1.2.1. 我们的无名氏祖先率先用上了火&#x…

编写商品列表和商品编辑和商品新增页面

addvue <template><!-- 传过来的id --> <!-- {{ $route.query.id }} --> <el-formref"FormRef"style"max-width: 600px":model"FormData":rule"rules"status-iconlabel-width"auto"class"demo-r…

Golang | Leetcode Golang题解之第232题用栈实现队列

题目&#xff1a; 题解&#xff1a; type MyQueue struct {inStack, outStack []int }func Constructor() MyQueue {return MyQueue{} }func (q *MyQueue) Push(x int) {q.inStack append(q.inStack, x) }func (q *MyQueue) in2out() {for len(q.inStack) > 0 {q.outStack…

【web】-sql注入-login

根据网址提示打开如图&#xff1a; 查看源代码前台并没有过滤限制、扫描后台也没有发现特殊文件。看到标题显示flag is in database&#xff0c;尝试sql注入。 由于post,bp抓包如下&#xff1a; 运行python sqlmap.py -r 1.txt --dump 获取flag 42f4ebc342b6ed4af4aadc1ea75f…

昇思25天学习打卡营第20天 | 基于MindNLP+MusicGen生成自己的个性化音乐

基于MindNLPMusicGen生成个性化音乐 实验简介 MusicGen是Meta AI提出的音乐生成模型&#xff0c;能够根据文本描述或音频提示生成高质量音乐。该模型基于Transformer结构&#xff0c;分为三个阶段&#xff1a;文本编码、音频token预测和音频解码。此实验将演示如何使用MindSpo…

搞定ES6同步与异步机制、async/await的使用以及Promise的使用!

文章目录 同步和异步async/awaitPromisePromise的概念 同步和异步 ​ 同步&#xff1a;代码按照编写顺序逐行执行&#xff0c;后续的代码必须等待当前正在执行的代码完成之后才能执行&#xff0c;当遇到耗时的操作&#xff08;如网络请求等&#xff09;时&#xff0c;主线程会…

数据结构(初阶2.顺序表)

文章目录 一、线性表 二、顺序表 2.1 概念和结构 2.2 分类 2.2.1 静态顺序表 2.2.2 动态顺序表 2.3动态顺序表的实现 1.SeqList.h 2.SeqList.c 打印顺序表 初始化 销毁 增容 尾插 头插 在指定位置之前插入数据 尾删 头删 在指定位置删除数据 3.test.c 一、线性表 线性表&#…

如何解决VMware 安装Windows10系统出现Time out EFI Network...

一、问题描述 使用VMware 17 安装windows10出现如下图所示Time out EFI Network… Windows10镜像为微软官方下载的ISO格式镜像&#xff1b; 二、问题分析 VMware 17 默认的固件类型是UEFI(E)&#xff0c;而微软官网下载的Windows10 ISO格式镜像不支持UEFI(E)&#xff0c;支…

【中项第三版】系统集成项目管理工程师 | 第 4 章 信息系统架构④ | 4.7

前言 第4章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节属于技术相关的内容&#xff0c;学习要以教材为准。本章分值预计在4-5分。 目录 4.7 安全架构 4.7.1 安全威胁 4.7.2 定义与范围 4.7.3 整体架构设计 4.7.4 网络安全架构设计 4.7.5 数据库系统安…

C++基础语法:STL之迭代器

前言 "打牢基础,万事不愁" .C的基础语法的学习 引入 C基础:STL概述-CSDN博客 上一篇梳理了一些同STL有关的概念.同时对理解迭代器需要的类包含,内部类,链表等内容做了分析,这篇从<C Prime Plus> 6th Edition(以下称"本书")的P684,大标题16.4泛型编…

C++继承和多态

目录 继承 继承的意义 访问限定符、继承方式 赋值兼容规则&#xff08;切片&#xff09; 子类的默认成员函数 多继承 继承is a和组合has a 多态 什么是多态 形成多态的条件 函数重载&#xff0c;隐藏&#xff0c;重写的区别 override和final 多态原理 继承 继承的…

Algorithms,最全的Python算法仓库!

学习编程、学习Python最好的方式就是练习&#xff0c;哪怕是新手&#xff0c;只要不断地敲代码输出&#xff0c;肯定会有神效。 Python的练手项目很多&#xff0c;特别是Github上&#xff0c;建议不管新手、老司机都去看看。 这里推荐给大家一个Gitthub上练习的项目&#xff…

[C++]——同步异步日志系统(5)

同步异步日志系统 一、日志消息格式化设计1.1 格式化子项类的定义和实现1.2 格式化类的定义和实现 二、日志落地类设计2.1 日志落地模块功能实现与测试2.2 日志落地模块功能功能扩展 一、日志消息格式化设计 日志格式化模块的作用&#xff1a;对日志消息进行格式化&#xff0c…