SpringBoot启动流程源码解析

目录

一、SpringApplication构造方法解析

1. web应用类型

2. BootstrapRegistryInitializer

3. ApplicationContextInitializer

4. ApplicationListener

5. 推断Main方法所在类

二、SpringApplication.run(String... args)方法解析

1.创建DefaultBootstrapContext

2.获取SpringApplicationRunListeners

3.调用SpringApplicationRunListener的starting()

4.创建和配置Environment

5.配置需要忽略的Bean

6.打印Banner

7.创建ApplicationContext(Spring容器)

8.准备ApplicationContext(Spring容器)

8.1 ApplicationContextInitializer初始化Spring容器

8.2 SpringApplicationRunListener的contextPrepared()

8.3 DefaultBootstrapContext调用close()

8.4 load()方法将启动类作为配置类注册到Spring容器

8.5 SpringApplicationRunListener的contextLoaded()

9. 刷新ApplicationContext(Spring容器)

10. SpringApplicationRunListener的started()

11. 执行Runners

12. SpringApplicationRunListener的running()

13. 出现异常执行SpringApplicationRunListener的failed()



一、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();this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}

1. web应用类型

private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };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";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;}

        如果项目依赖中存在org.springframework.web.reactive.DispatcherHandler,同时不存在org.springframework.web.servlet.DispatcherServlet,那么应用类型为WebApplicationType.REACTIVE

        如果项目依赖中不存在org.springframework.web.reactive.DispatcherHandler,同时也不存在org.springframework.web.servlet.DispatcherServlet,那么应用类型为WebApplicationType.NONE

        否则,应用类型为WebApplicationType.SERVLET

2. BootstrapRegistryInitializer

        从META-INF/spring.factories中读取键值为BootstrapRegistryInitializer类型的扩展点,并实例化出对应扩展对象实例

        BootstrapRegistryInitializer的作用是可以初始化BootstrapRegistry

        BootstrapRegistry时一个简单的对象注册表,在启动和 Environment 处理期间可用,直到准备完成 ApplicationContext(Spring 容器) 为止。可用于注册创建实例,或者完成ApplicationContext (Spring 容器)后共享一些实例

3. ApplicationContextInitializer

        从META-INF/spring.factories中读取键值为ApplicationContextInitializer类型的扩展点,并实例化出对应扩展对象实例

        ApplicationContextInitializer是用来初始化Spring容器ApplicationContext对象的,比如可以利用ApplicationContextInitializer来向Spring容器中添加ApplicationListener

4. ApplicationListener

        从"META-INF/spring.factories"中读取键值为ApplicationListener类型的扩展点,并实例化出对应扩展对象

5. 推断Main方法所在类

private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null;}

根据当前线程的调用栈来判断main()方法在哪个类,哪个类就是Main类。

二、SpringApplication.run(String... args)方法解析

public ConfigurableApplicationContext run(String... args) {long startTime = System.nanoTime();DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}listeners.started(context, timeTakenToStartup);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;}

1.创建DefaultBootstrapContext

        使用SpringApplication构造方法中创建的BootstrapRegistryInitializer初始化DefaultBootstrapContext对象

2.获取SpringApplicationRunListeners

        从"META-INF/spring.factories"中读取键值为SpringApplicationRunListeners类型的扩展点,并实例化出对应扩展对象

3.调用SpringApplicationRunListener的starting()

        SpringBoot默认提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口,默认情况下会利用EventPublishingRunListener发布一个ApplicationStartingEvent事件,可以通过定义ApplicationListener来消费监听这个事件

4.创建和配置Environment

        Environment对象表示环境变量,该对象内部主要包含了:操作系统环境变量、JVM配置信息、-D方式所配置的JVM环境变量

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(bootstrapContext, environment);DefaultPropertiesPropertySource.moveToEnd(environment);Assert.state(!environment.containsProperty("spring.main.environment-prefix"),"Environment prefix cannot be set via properties.");bindToSpringApplication(environment);if (!this.isCustomEnvironment) {EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}

        SpringApplicationRunListener的environmentPrepared()

        默认情况下会利用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,可以通过定义ApplicationListener来消费这个事件,比如默认情况下会有一个EnvironmentPostProcessorApplicationListener来消费这个事件,而这个ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件并添加到Environment对象中。

5.配置需要忽略的Bean

public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {Boolean ignore = environment.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,Boolean.class, Boolean.TRUE);System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());}}

6.打印Banner

        SpringApplicationBannerPrinter

7.创建ApplicationContext(Spring容器)

        使用ApplicationContextFactory.DEFAULT根据应用类型创建对应的Spring容器

public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {return (webApplicationType != WebApplicationType.SERVLET) ? null: new AnnotationConfigServletWebServerApplicationContext();}

        应用类型为SERVLET,则对应AnnotationConfigServletWebServerApplicationContext

        应用类型为REACTIVE,则对应AnnotationConfigReactiveWebServerApplicationContext

        应用类型为普通类型,则对应AnnotationConfigApplicationContext

        一般使用的应用类型为SERVLET:AnnotationConfigServletWebServerApplicationContext

8.准备ApplicationContext(Spring容器)

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);postProcessApplicationContext(context);applyInitializers(context);listeners.contextPrepared(context);bootstrapContext.close(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));listeners.contextLoaded(context);}

8.1 ApplicationContextInitializer初始化Spring容器

        默认SpringBoot提供了多个ApplicationContextInitializer,其中比较重要的有ConditionEvaluationReportLoggingListener

@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {this.applicationContext = applicationContext;applicationContext.addApplicationListener(new ConditionEvaluationReportListener());if (applicationContext instanceof GenericApplicationContext) {// Get the report early in case the context fails to loadthis.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());}}

        在该类的initialize()方法中:

        将Spring容器赋值给它的applicationContext属性

        并且往Spring容器中添加一个ConditionEvaluationReportListener(ConditionEvaluationReportLoggingListener的内部类),它是一个ApplicationListener

        并生成一个ConditionEvaluationReport对象赋值给它的report属性

        ConditionEvaluationReportListener会负责接收ContextRefreshedEvent事件,也就是Spring容器启动完毕就会触发ContextRefreshedEvent,ConditionEvaluationReportListener就会打印自动配置类的条件评估报告。

	protected void onApplicationEvent(ApplicationEvent event) {ConfigurableApplicationContext initializerApplicationContext = this.applicationContext;if (event instanceof ContextRefreshedEvent) {if (((ApplicationContextEvent) event).getApplicationContext() == initializerApplicationContext) {logAutoConfigurationReport();}}else if (event instanceof ApplicationFailedEvent&& ((ApplicationFailedEvent) event).getApplicationContext() == initializerApplicationContext) {logAutoConfigurationReport(true);}}

8.2 SpringApplicationRunListener的contextPrepared()

        默认会利用EventPublishingRunListener发布一个ApplicationContextInitializedEvent事件,默认情况没有ApplicationListener消费该事件

8.3 DefaultBootstrapContext调用close()

        关闭时要调用BootstrapContext的方法


8.4 load()方法将启动类作为配置类注册到Spring容器

8.5 SpringApplicationRunListener的contextLoaded()

        默认会利用EventPublishingRunListener发布一个ApplicationPreparedEvent事件

	@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {for (ApplicationListener<?> listener : this.application.getListeners()) {if (listener instanceof ApplicationContextAware) {((ApplicationContextAware) listener).setApplicationContext(context);}context.addApplicationListener(listener);}this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));}

9. 刷新ApplicationContext(Spring容器)

        调用Spring容器的refresh()方法:

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();contextRefresh.end();}}}

        ServletWebServerApplicationContext在重写onRefresh方法,在该方法中创建了WebServer,默认启动Tomcat服务器。

@Overrideprotected void onRefresh() {super.onRefresh();try {createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}}

10. SpringApplicationRunListener的started()

        发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件,AvailabilityChangeEvent事件表示状态变更状态,变更后的状态为LivenessState.CORRECT

@Overridepublic void started(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);}public enum LivenessState implements AvailabilityState {/*** The application is running and its internal state is correct.*/CORRECT,/*** The application is running but its internal state is broken.*/BROKEN}

11. 执行Runners

        获取Spring容器中的ApplicationRunner和CommandLineRunner类型的Bean,然后按顺序调用他们的run()方法

private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());AnnotationAwareOrderComparator.sort(runners);for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}}

12. SpringApplicationRunListener的running()

        发布ApplicationReadyEvent事件和AvailabilityChangeEvent事件,AvailabilityChangeEvent事件表示状态变更状态,变更后的状态为ReadinessState.ACCEPTING_TRAFFIC

@Overridepublic void running(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);}public enum ReadinessState implements AvailabilityState {/*** The application is ready to receive traffic.*/ACCEPTING_TRAFFIC,/*** The application is not willing to receive traffic.*/REFUSING_TRAFFIC}

13. 出现异常执行SpringApplicationRunListener的failed()

        发布ApplicationFailedEvent事件

@Overridepublic void failed(ConfigurableApplicationContext context, Throwable exception) {ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);if (context != null && context.isActive()) {// Listeners have been registered to the application context so we should// use it at this point if we cancontext.publishEvent(event);}else {// An inactive context may not have a multicaster so we use our multicaster to// call all of the context's listeners insteadif (context instanceof AbstractApplicationContext) {for (ApplicationListener<?> listener : ((AbstractApplicationContext) context).getApplicationListeners()) {this.initialMulticaster.addApplicationListener(listener);}}this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());this.initialMulticaster.multicastEvent(event);}}

至此Springboot的启动执行流程全部完成。

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

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

相关文章

订单超时自动取消的实践方案

1、定时任务方案 方案流程&#xff1a; 每隔 30 秒查询数据库&#xff0c;取出最近的 N 条未支付的订单。 遍历查询出来的订单列表&#xff0c;判断当前时间减去订单的创建时间是否超过了支付超时时间&#xff0c;如果超时则对该订单执行取消操作。 定时任务方案工程实现相…

【Vue】vue中将 html 或者 md 导出为 word 文档

原博主 xh-htmlword文档 感谢这位大佬的封装优化和分享&#xff0c;亲测有用&#xff01;可以去看大佬&#x1f447;的说明&#xff01; 前端HTML转word文档&#xff0c;绝对有效&#xff01;&#xff01;&#xff01; 安装 npm install xh-htmlword导入 import handleEx…

远动通讯屏的作用

远动通讯屏的作用 远动通讯屏有时有称为调度数据网柜&#xff0c;远动通讯屏具体干啥作用&#xff1f;远动通讯屏是以计算机为基础的生产过程与调度自动化系统&#xff0c;可以对现场的运行设备进行监视和控制、以实现数据采集、设备测量、参数调节以及各类信号报警等各项功能。…

用webui.sh安装报错No module named ‘importlib.metadata‘

安装sdweb报错&#xff0c;出现No module named importlib.metadata&#xff1a; glibc version is 2.35 Cannot locate TCMalloc. Do you have tcmalloc or google-perftool installed on your system? (improves CPU memory usage) Traceback (most recent call last):File…

堆的基本操作(c语言实现)

1.堆的基本操作 1.1定义堆 typedef int HPDataType;//堆中存储数据的类型typedef struct Heap {HPDataType* a;//用于存储数据的数组int size;//记录堆中已有元素个数int capacity;//记录堆的容量 }HP;1.2初始化堆 然后我们需要一个初始化函数&#xff0c;对刚创建的堆进行初…

【C语言】路漫漫其修远兮,深入[指针]正当下

一. 指针初步 1.概念定义 地址&#xff1a;我们在内存中开辟空间时&#xff0c;为了方便后续访问&#xff0c;每个数据有确切的地址。 指针&#xff1a;指向数据的地址&#xff0c;并将其地址储存在指针变量中。 2.基本运算符 • 取地址操作符&#xff08;&&#xff09; …

【强化学习入门】基于DDPG的强化学习控制器设计

最近在看控制领域研究热门–强化学习相关的东西&#xff0c;跟着matlab官方强化学习教程一边看一边学&#xff0c;感觉入门门槛略高&#xff0c;需要补很多机器学习相关的知识&#xff0c;高数概率论那些&#xff0c;摸索了个把月感觉现在只大概会用&#xff0c;原理啥的还没搞…

进口家装水管十大品牌哪家好,弗锐德为您推荐进口家装水管领先十大品牌

水管作为家装隐蔽工程之一&#xff0c;选对一款优质的水管是至关重要的&#xff0c;毕竟好的水管能够保证家庭后续几十年的用水安全和健康。今天&#xff0c;小编就和大家说说进口家装水管十大品牌哪家好&#xff1f; 目前国内进口家装水管具有知名度和消费者认可的品牌有&…

自制一个3D打印的移动终端——T3rminal

T3rminal是我过去几个月一直在努力开发的一个CyberDeck&#xff0c;并希望将其开源。 我从不同设备如Decktility、YARH和其他项目中获得了灵感。 你可以在我的Github上协助并关注该项目&#xff1a;https://github.com/crazycaleb2008/T3rminal/tree/main/3D%20Models 材料 …

Edge的使用心得和深度探索-Sider: ChatGPT 侧边栏

作为一款备受欢迎的网络浏览器&#xff0c;Microsoft Edge在用户体验和功能方面都有着诸多优势。在长期的使用中&#xff0c;我总结出了三条使用心得&#xff0c;同时也发现了三个能够极大提高效率的功能。让我们一起深度探索Edge的潜力吧&#xff01; 使用心得&#xff1a; 界…

Spring 常用的注入方式有什么?

Spring 是一个非常流行的 Java 开发框架&#xff0c;它提供了多种依赖注入&#xff08;Dependency Injection&#xff09;的方式&#xff0c;使得开发者可以轻松地管理应用程序中的组件依赖关系。在 Spring 中&#xff0c;常用的注入方式主要包括构造器注入、Setter 方法注入、…

【测试报告】星光日册

⭐ 作者&#xff1a;Jwenen &#x1f331; 作者主页&#xff1a;Jwenen的个人主页 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 测试报告 1. 项目介绍2. 测试用例框架3. 自动化测试源码 1. 项目介绍 “星光日册”项目实现了用…

继续SQL

主知识点六&#xff1a;having 聚合前的筛选用where&#xff0c;聚合后的筛选用having Having和where的区别是&#xff1a;运行顺序和对象不用 Having是在group by聚合后的基础上进行筛选。 ● 【例题27*】&#xff08;运行原理&#xff09;查询总人口数至少为3亿的大洲和…

vxe-table 区域选取、复制粘贴功能,的基本使用

vxe-table区域选取、复制粘贴功能&#xff0c;的基本使用&#xff08;注&#xff1a;该功能仅支持企业版&#xff0c;这里仅供部分演示&#xff09; 1.鼠标区域选择功能&#xff1a; 参数说明&#xff1a; mouse-config.area 是否开启鼠标单元格区域选取 <template>&l…

详解基于 RAG 的 txt2sql 全过程

前文 本文使用通义千问大模型和 ChromaDB 向量数据库来实现一个完整的 text2sql 的项目&#xff0c;并基于实际的业务进行效果的展示。 准备 在进行项目之前需要准备下面主要的内容&#xff1a; python 环境通义千问 qwen-max 模型的 api-keyChromaDB 向量数据库acge_text_…

Linux-笔记 uboot修改设备树

1. FDT介绍 扁平设备树&#xff08;Flattened Device Tree&#xff0c;FDT&#xff09;&#xff0c;也叫平坦设备树&#xff0c;是设备树的一种二进制表示形式&#xff0c;提高了在嵌入式系统中的传输和解析效率&#xff1b; 2. 在U-Boot中使用FDT 2.1. 进入U-Boot 开发板上…

OpenCV 入门(四)—— 车牌号识别

OpenCV 入门系列&#xff1a; OpenCV 入门&#xff08;一&#xff09;—— OpenCV 基础 OpenCV 入门&#xff08;二&#xff09;—— 车牌定位 OpenCV 入门&#xff08;三&#xff09;—— 车牌筛选 OpenCV 入门&#xff08;四&#xff09;—— 车牌号识别 OpenCV 入门&#xf…

【论文阅读】VMamba: Visual State Space Model

VMamba:视觉状态空间模型 code&#xff1a;https://github.com/MzeroMiko/VMamba Background ​ CNN拥有线性复杂度因而可以处理高分辨率的图像&#xff0c;而ViT在拟合能力方面超过了CNN&#xff0c;但ViT是二次复杂度&#xff0c;在处理高分辨率图像时计算开销较大。ViT通过…

Wappalyzer指纹识别下载安装使用教程,图文教程(超详细)

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

Windows平台通过MobaXterm远程登录安装在VMware上的Linux系统(CentOS)

MobaXterm是一个功能强大的远程计算工具&#xff0c;它提供了一个综合的远程终端和图形化的X11服务器。MobaXterm旨在简化远程计算任务&#xff0c;提供了许多有用的功能&#xff0c;使远程访问和管理远程服务器变得更加方便&#xff0c;它提供了一个强大的终端模拟器&#xff…