【Springboot】介绍启动类和启动过程

  • 【一】Spring Boot 启动类的注解
    • 【1】核心注解:@SpringBootApplication
      • (1)​@SpringBootConfiguration​:Spring容器会从该类中加载Bean定义
      • (2)​@EnableAutoConfiguration​:自动配置依赖
      • (3)​@ComponentScan​:​自动扫描并注册Bean
    • 【2】其他常用注解(可根据需要添加)
    • 【3】@MapperScan
    • 【4】自动装配原理
      • (1)自动装配的核心思想
      • (2)实现原理的核心组件
  • 【二】Spring Boot 项目启动的详细流程
    • 【1】​启动 Main 方法​
    • 【2】​创建 SpringApplication 实例​:
    • 【3】​运行 SpringApplication 实例(run方法)​​:这是最复杂的核心阶段。
  • 【三】Spring Boot 生命周期中的扩展点及使用案例
    • 【1】Application Events(应用事件) - 观察者模式
    • 【2】ApplicationContextInitializer(应用上下文初始化器)
    • 【3】CommandLineRunner / ApplicationRunner
    • 【4】Spring Bean 生命周期钩子
  • 【四】Spring Bean 生命周期中的重要组件
    • 【1】BeanPostProcessor (BPP) - 容器级后处理器​
    • 【2】BeanFactoryPostProcessor (BFPP) - 工厂级后处理器​
    • 【3】Aware 接口族 - 感知接口​
    • 【4】生命周期回调注解/接口​
    • 【5】生命周期执行顺序

【一】Spring Boot 启动类的注解

Spring Boot 启动类通常就是一个标注了 @SpringBootApplication的类,但这个注解是一个组合注解(Composite Annotation)​,理解它包含的元注解是关键。

【1】核心注解:@SpringBootApplication

这是启动类上唯一必须的注解,它整合了三个核心注解的功能:

(1)​@SpringBootConfiguration​:Spring容器会从该类中加载Bean定义

(1)​作用​:表明当前类是一个配置类。它的底层是 @Configuration,这意味着Spring容器会从该类中加载Bean定义(@Bean注解的方法)。
(2)​为什么不用 @Configuration​:@SpringBootConfiguration是Spring Boot提供的,语义上更明确地指出这是主配置类,但在功能上与 @Configuration无异。

(2)​@EnableAutoConfiguration​:自动配置依赖

(1)​作用​:​启用Spring Boot的自动配置机制。这是Spring Boot魔法(Convention over Configuration)的核心。
(2)​原理​:这个注解会通知Spring Boot根据你添加的jar包依赖(如classpath下是否存在DataSource、SpringMVC等类),自动猜测并配置你需要的Bean。例如,当你引入了spring-boot-starter-web,它会自动配置Tomcat和Spring MVC。

(3)​@ComponentScan​:​自动扫描并注册Bean

(1)​作用​:​自动扫描并注册Bean。默认会扫描启动类所在包及其所有子包下的所有组件,包括@Component, @Service, @Repository, @Controller等注解的类,并将它们注册到Spring容器中。
(2)​重要提示​:这是为什么通常要把启动类放在项目根包(root package)下的原因。如果放在一个很深的包里,@ComponentScan可能无法扫描到其他重要的组件。

【2】其他常用注解(可根据需要添加)

虽然 @SpringBootApplication已经足够,但在某些场景下,你可能会在启动类上额外添加一些注解。
(1)​@EnableScheduling​
​作用​:启用Spring的定时任务功能。添加后,可以使用 @Scheduled注解来创建定时任务。

(2)​@EnableAsync​
​作用​:启用Spring的异步方法执行功能。添加后,可以使用 @Async注解来标记异步执行的方法。

(3)​@EnableTransactionManagement​
​作用​:启用注解式事务管理。不过,当Spring Boot检测到存在事务管理器(如引入了JDBC或JPA starter)时,此功能实际上是默认开启的。显式添加此注解只是为了代码意图更清晰。

(4)​@EnableCaching​
​作用​:启用Spring的注解驱动缓存功能。添加后,可以使用 @Cacheable, @CacheEvict等注解。

(5)​@Import​
​作用​:用于导入其他配置类(通常是@Configuration类),这些配置类可能不在@ComponentScan的扫描路径下。例如:@Import({CustomConfig.class, AnotherConfig.class})。

​总结​:对于大多数标准应用,​只使用 @SpringBootApplication注解就足够了。其他注解如 @EnableScheduling等,应根据具体功能需求选择性添加。

【3】@MapperScan

@MapperScan注解的主要目的是告诉 MyBatis 应该去哪个或哪些包路径下扫描 Mapper 接口,并自动将其注册为 Spring 容器中的 Bean(MapperFactoryBean)​。
(1)​解决了什么问题?​​
在没有这个注解之前,你需要在每个 Mapper 接口上手动添加 @Mapper注解,或者手动配置 MapperFactoryBean,非常繁琐。@MapperScan通过包扫描的方式,实现了批量、自动的注册,极大简化了配置。

(2)​底层机制:​​
当 Spring 容器启动时,它会处理 @MapperScan注解。MyBatis-Spring 整合模块会为指定的包路径创建 ClassPathMapperScanner,该扫描器会找到所有接口,并为每个接口动态创建一个 MapperFactoryBean的 BeanDefinition 注册到 Spring 容器中。MapperFactoryBean是一个 FactoryBean,它的 getObject()方法会使用 SqlSession为原始 Mapper 接口创建一个动态代理实例,并将这个代理实例作为 Bean 交给 Spring 管理。这就是为什么你可以在 Service 层直接 @Autowired一个接口的原因。

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import @SpringBootApplication// 方式一:直接扫描一个包
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}// 方式二:扫描多个包
@MapperScan(basePackages = {"com.example.mapper", "com.example.other.dao"})// 方式三:类型安全的扫描(推荐)
// 创建一个空的标记接口,放在 com.example.mapper 包下
public interface MapperScanMarker {// 无任何方法,仅作为包路径标记
}@SpringBootApplication
// 扫描标记接口所在的包
@MapperScan(basePackageClasses = MapperScanMarker.class)
public class DemoApplication {// ...
}

【4】自动装配原理

(1)自动装配的核心思想

​要解决的问题:​​ 传统 Spring 应用需要大量手动配置(如 XML、Java Config)来集成第三方库或框架(例如数据源、事务管理器、MVC 等)。这个过程繁琐且容易出错。

​解决方案:​​ Spring Boot 自动装配通过预先定义的条件,在检测到项目的特定依赖、配置和类路径后,自动为应用注入所需的 Bean 并完成配置。简单来说,就是 ​​“如果我在类路径上看到了 X,并且你没有自己配置 Y,那么我就自动给你配置一个默认的 Y”​。

(2)实现原理的核心组件

(1)@SpringBootApplication与 @EnableAutoConfiguration
一切的起点是主启动类上的 @SpringBootApplication注解。它是一个组合注解​(Composite Annotation),其核心功能之一由 @EnableAutoConfiguration提供。

@SpringBootApplication // 这是一个元注解,整合了其他注解的功能
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

@EnableAutoConfiguration本身又是一个开关注解,它通过 @Import导入了最核心的加载器:AutoConfigurationImportSelector。

(2)AutoConfigurationImportSelector
这个类是自动装配的大脑。它的核心任务是决定需要导入哪些自动配置类。
​工作原理​:AutoConfigurationImportSelector会读取项目 classpath 下所有 JAR 包中的 ​META-INF/spring.factories​ 文件。
​关键文件​:在 spring-boot-autoconfigure-x.x.x.x.jar中,META-INF/spring.factories文件是一个键值对形式的配置文件。其中 EnableAutoConfiguration这个 key 后面列出了一长串的自动配置类(XXXAutoConfiguration)。
​spring.factories文件片段示例:​​

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
# ... 省略上百个配置类
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

AutoConfigurationImportSelector会获取所有这些配置类的全限定名,并将它们作为候选配置类。

(3)@Conditional条件注解家族 - ​灵魂所在​
仅仅将候选配置类全部加载是不行的,Spring Boot 需要根据当前应用的环境来智能判断哪些配置类应该真正生效。这就是 @Conditional系列注解的作用。

这些注解是自动装配的“开关”,它们会在配置类或 Bean 被加载前进行条件判断,只有满足所有条件,配置才会生效。

(4)XXXAutoConfiguration自动配置类
这些是具体的执行者。每个 XXXAutoConfiguration都是一个标准的 ​Spring 配置类​(@Configuration),其内部使用 @Bean方法来定义组件,并且方法上通常装饰着各种 @Conditional注解。

【二】Spring Boot 项目启动的详细流程

Spring Boot 的启动流程可以看作是传统 Spring 应用启动流程的一个高度封装和自动化版本。其核心是 SpringApplication.run(Application.class, args)方法。
以下是其详细步骤:

【1】​启动 Main 方法​

JVM 调用应用程序的 main方法。

【2】​创建 SpringApplication 实例​:

(1)在 run方法内部,首先会创建一个 SpringApplication实例。
(2)这个实例会进行一些初始化工作,例如:
1-​推断应用类型​:判断是普通的Servlet应用(Spring MVC)还是响应式Web应用(WebFlux)。
​2-初始化器(Initializers)​​:加载 META-INF/spring.factories文件中配置的 ApplicationContextInitializer。
​3-监听器(Listeners)​​:加载 META-INF/spring.factories文件中配置的 ApplicationListener(应用监听器)。这些监听器将用于接收整个启动过程中发布的各种事件。

【3】​运行 SpringApplication 实例(run方法)​​:这是最复杂的核心阶段。

(1)​a. 启动计时器 & 发布开始事件​:启动一个计时器,并发布 ApplicationStartingEvent事件。此时容器还未创建,任何Bean都未初始化。
(2)​b. 准备环境(Environment)​​:创建并配置应用运行环境(Environment),读取所有配置源(application.properties/yaml、系统属性、环境变量等)。发布 ApplicationEnvironmentPreparedEvent事件。
(3)​c. 创建应用上下文(ApplicationContext)​​:根据第一步推断的应用类型,创建对应的 ApplicationContext(例如,对于Servlet应用,创建 AnnotationConfigServletWebServerApplicationContext)。
(4)​d. 准备应用上下文​:
将环境(Environment)设置到上下文中。
执行所有 ApplicationContextInitializer的 initialize方法,对上下文进行自定义初始化。
发布 ApplicationContextInitializedEvent事件。
(5)​e. 刷新应用上下文(核心中的核心)​​:调用上下文的 refresh()方法。这一步完成了传统Spring应用容器的所有初始化工作:
​加载Bean定义​:解析启动类(因为它是@Configuration),执行@ComponentScan扫描并注册所有Bean定义。
​执行自动配置​:执行 @EnableAutoConfiguration逻辑,加载 spring-boot-autoconfigurejar 包中 META-INF/spring.factories文件里的所有自动配置类(XXXAutoConfiguration),根据条件(@ConditionalOnXxx)判断是否需要配置相应的Bean。
​初始化Bean​:实例化所有非懒加载的单例Bean。
(6)​f. 后置处理​:执行 CommandLineRunner和 ApplicationRunner接口的实现Bean。
(7)​g. 启动完成​:发布 ApplicationStartedEvent事件,启动计时器停止,打印启动耗时日志。
整个流程伴随着事件的发布,允许开发者通过监听这些事件在特定阶段插入自定义逻辑。

【三】Spring Boot 生命周期中的扩展点及使用案例

Spring Boot 在整个生命周期中提供了大量“钩子”(Hook),允许开发者介入并执行自定义逻辑。以下是一些最重要的扩展点:

【1】Application Events(应用事件) - 观察者模式

通过实现 ApplicationListener接口或使用 @EventListener注解来监听特定事件。
​常用事件​:
ApplicationStartingEvent:应用刚启动,任何处理都还未进行。
ApplicationEnvironmentPreparedEvent:环境已准备完毕,上下文还未创建。
ApplicationContextInitializedEvent:上下文已创建且初始化器已被调用,但Bean定义还未加载。
ApplicationPreparedEvent:Bean定义已加载,但Bean还未实例化。
ApplicationStartedEvent:上下文已刷新,所有Bean已实例化,CommandLineRunner/ApplicationRunner还未执行。
ApplicationReadyEvent:应用已完全启动,可以正常接收请求。
​案例:在应用启动成功后打印一条日志​java

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class StartupNotifier {@EventListener(ApplicationReadyEvent.class)public void onAppReady() {System.out.println("🎉 Application is now ready and can serve traffic!");// 可以在这里执行一些启动后的检查,比如检查数据库连接状态等}
}

【2】ApplicationContextInitializer(应用上下文初始化器)

在 ApplicationContext刷新(refresh)之前,对其执行自定义的初始化操作。
​案例:在上下文准备阶段设置一个自定义属性​java

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {// 向环境中添加一个属性applicationContext.getEnvironment().getSystemProperties().put("myCustomProperty", "initialized");}
}

​注册方式​:需要在 META-INF/spring.factories文件中注册。

复制org.springframework.context.ApplicationContextInitializer=com.example.MyInitializer

【3】CommandLineRunner / ApplicationRunner

在应用上下文刷新完成后、应用完全启动之前,执行一些特定的代码。非常适合进行数据初始化、缓存预热等操作。两者功能几乎一样,区别在于参数:
CommandLineRunner:提供原始的字符串数组参数 String… args(即main方法的args)。
ApplicationRunner:提供更结构化的 ApplicationArguments对象来解析参数。
​案例:应用启动后初始化一些数据​java

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class DataLoader implements CommandLineRunner {private final UserRepository userRepository;public DataLoader(UserRepository userRepository) {this.userRepository = userRepository;}@Overridepublic void run(String... args) throws Exception {// 检查数据库是否已有数据,如果没有则插入默认数据if (userRepository.count() == 0) {User admin = new User("admin", "admin@example.com");userRepository.save(admin);System.out.println("Initial admin user created.");}}
}

【4】Spring Bean 生命周期钩子

这是 Spring 框架本身的扩展点,在 Spring Boot 中同样适用。
@PostConstruct:在Bean的依赖注入完成后,初始化方法(InitializingBean.afterPropertiesSet)之前执行。
InitializingBean接口:实现 afterPropertiesSet()方法,在所有属性设置完成后执行。
@PreDestroy:在Bean被容器销毁之前执行。
​案例:Bean初始化后连接资源​java

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Component
public class ResourceConnector {@PostConstructpublic void connect() {System.out.println("Connecting to external resource...");// 初始化连接}@PreDestroypublic void disconnect() {System.out.println("Disconnecting from external resource...");// 关闭连接,释放资源}
}

【四】Spring Bean 生命周期中的重要组件

【1】BeanPostProcessor (BPP) - 容器级后处理器​

(1)​作用​:这是Spring框架最强大、最核心的扩展接口。它作用于整个ApplicationContext,对所有Bean的初始化过程进行拦截和增强。你可以把它想象成一个“Bean加工流水线”。
(2)​两个核心方法​:
1-postProcessBeforeInitialization(Object bean, String beanName):在Bean的初始化回调方法​(如@PostConstruct)之前执行。可以对Bean进行包装或替换(例如返回一个代理对象,AOP就是基于此实现的)。
2-postProcessAfterInitialization(Object bean, String beanName):在Bean的初始化回调方法之后执行。此时Bean已基本完成初始化。
(3)​重要实现​:AutowiredAnnotationBeanPostProcessor(处理@Autowired注解)、CommonAnnotationBeanPostProcessor(处理@PostConstruct、@Resource等)、AnnotationAwareAspectJAutoProxyCreator(负责AOP动态代理)。

【2】BeanFactoryPostProcessor (BFPP) - 工厂级后处理器​

(1)​作用​:在Bean实例化之前,可以读取、修改Bean的定义(BeanDefinition)。它操作的是“蓝图”,而不是Bean实例本身。
(2)​核心方法​:postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
(3)​经典案例​:PropertySourcesPlaceholderConfigurer(处理 ${…}占位符)就是在此时将Bean定义中的占位符替换为实际的属性值。

【3】Aware 接口族 - 感知接口​

​(1)作用​:让Bean能“感知”到容器本身和某些特定的资源。这些接口的回调发生在BeanPostProcessor之前,初始化方法之后。
(2)​常用接口​:
1-BeanNameAware:感知自己在容器中的Bean名称。
2-ApplicationContextAware:感知自己所在的ApplicationContext(这是手动获取Bean的一种方式)。
3-BeanFactoryAware:感知创建自己的BeanFactory。

【4】生命周期回调注解/接口​

(1)​作用​:定义Bean自身初始化和销毁时的行为。
(2)​初始化​:
​JSR-250注解​:@PostConstruct(推荐使用,标准注解)。
​Spring接口​:InitializingBean及其 afterPropertiesSet()方法。
​XML配置​:init-method属性。
(3)​销毁​:
​JSR-250注解​:@PreDestroy(推荐使用)。
​Spring接口​:DisposableBean及其 destroy()方法。
​XML配置​:destroy-method属性。

【5】生命周期执行顺序

​执行顺序​:BeanFactoryPostProcessor-> BeanPostProcessor的Before-> Aware接口 -> @PostConstruct-> InitializingBean-> init-method-> BeanPostProcessor的After-> … -> @PreDestroy-> DisposableBean-> destroy-method。

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

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

相关文章

Gears实测室:第一期·音游跨设备性能表现与工具价值实践

在音游品类中&#xff0c;《跳舞的线》以 “音乐与操作节奏深度绑定” 的玩法特性&#xff0c;对设备性能提出了特殊要求 —— 稳定的帧率与低延迟的渲染响应&#xff0c;直接影响玩家对音符时机的判断&#xff0c;一旦出现卡顿或帧波动&#xff0c;易导致操作失误&#xff0c;…

格式刷+快捷键:Excel和WPS表格隔行填充颜色超方便

有时候我们会对Excel或WPS表格的数据区域每隔一行填充一个底纹&#xff0c;便于阅读和查看。可以使用条件格式搭配公式实现&#xff0c;也可以手动设置。通常手动设置的时候是先设置一行&#xff0c;然后再双击格式刷应用。可以有更快的方式&#xff1a;先设置一行底纹&#xf…

将现有Spring Boot项目作为模块导入到另一个Spring Boot项目

将现有Spring Boot项目作为模块导入到另一个Spring Boot项目的操作步骤如下&#xff1a;‌项目结构调整‌将待导入的项目文件夹复制到主项目的根目录下修改子模块目录名保持命名规范&#xff08;如ms-xxx格式&#xff09;‌父POM配置‌在主项目的pom.xml中添加<modules>声…

激光频率梳 3D 轮廓测量 - 铣刀刀片的刀口钝化值 R 的测量

一、引言铣刀刀片的刀口钝化值 R 是影响切削性能的关键参数&#xff0c;其精度直接关系到工件表面质量与刀具寿命。传统测量方法在面对微米级钝化圆角时存在分辨率不足、接触式测量易损伤刃口等问题。激光频率梳 3D 轮廓测量技术凭借飞秒级时频基准与亚微米级测量精度&#xff…

3-10〔OSCP ◈ 研记〕❘ WEB应用攻击▸XSS攻击理论基础

郑重声明&#xff1a; 本文所有安全知识与技术&#xff0c;仅用于探讨、研究及学习&#xff0c;严禁用于违反国家法律法规的非法活动。对于因不当使用相关内容造成的任何损失或法律责任&#xff0c;本人不承担任何责任。 如需转载&#xff0c;请注明出处且不得用于商业盈利。 …

《嵌入式硬件(四):温度传感器DS1820》

一、DS1820的引脚DS1820单总线数字温度计&#xff1a;异步串行半双工特性&#xff1a;1&#xff09;独特的单线接口&#xff0c;只需 1 个接口引脚即可通信2&#xff09;多点&#xff08;multidrop&#xff09;能力使分布式温度检测应用得以简化3&#xff09;不需要外部元件4&a…

langchain 输出解析器 Output Parser

示例中使用的公共代码&#xff1a; from langchain_deepseek import ChatDeepSeek chat ChatDeepSeek(model"deepseek-chat",temperature0,api_keyAPI_KEY, )使用方法&#xff1a; 引入解析器实例化解析器调用解析器的get_format_instructions()获得提示词&#xff…

LeetCode算法日记 - Day 37: 验证栈序列、N叉树的层序遍历

目录 1. 验证栈序列 1.1 题目解析 1.2 解法 1.3 代码实现 2. N叉树的层序遍历 2.1 题目解析 2.2 解法 2.3 代码实现 1. 验证栈序列 https://leetcode.cn/problems/validate-stack-sequences/description/ 给定 pushed 和 popped 两个序列&#xff0c;每个序列中的 值…

金融数据库--3Baostock

一、 Baostock 是什么&#xff1f;Baostock&#xff08;宝硕股票&#xff09;是一个免费、开源的证券数据平台&#xff08;SDK&#xff09;&#xff0c;旨在为金融量化投资者、研究人员和学生提供稳定、准确、易用的A股历史数据和相关金融数据。其核心是一个 Python 库&#xf…

微信小程序-1-微信开发者工具环境搭建和初始化创建项目

文章目录1 小程序概述1.1 什么是微信小程序1.2 大前端概念1.3 账号注册1.4 开发流程1.5 小程序成员2 创建项目2.1 创建项目流程2.2 创建项目2.3 本地开发支持http3 项目目录3.1 项目目录结构3.2 配置文件3.2.1 app.json(全局配置)3.2.2 xxx.json(页面配置)3.2.3 project.config…

Go语言开发AI应用

为什么选择Go语言开发AI应用在人工智能快速发展的今天&#xff0c;选择合适的编程语言对于AI应用的成功至关重要。虽然Python长期以来被认为是AI开发的首选语言&#xff0c;但Go语言正在逐渐崭露头角&#xff0c;成为AI应用开发的有力竞争者。Go语言的核心优势1. 卓越的性能表现…

10. 游戏开发中的TCP与UDP

1.TCP和UDP 2.TCP为什么慢于UDP 3.可靠UDP1.TCP和UDP 1).通过打电话的方式说明TCP和UDPa.TCP(传输控制协议), 就像打电话- 需要先拨号, 接通, 问候(建立连接)- 你一句, 我一句, 对方没有听清会要求你重复(确认与重传)- 保证对话有条不紊, 内容准确无误(可靠, 有序)- 如果信号不…

CMap常用函数

CMap 是 MFC 中用于存储键值对&#xff08;key-value&#xff09;的关联容器类&#xff0c;类似于 C 标准库中的 std::map&#xff0c;但依赖 MFC 框架实现。它采用哈希表&#xff08;Hash Table&#xff09;作为底层数据结构&#xff0c;支持高效的键值查找、插入和删除操作。…

Rocky9.0去堆叠双发arp(支持“ARP 广播双发”)

摘要 在去堆叠/MLAG 场景下&#xff0c;默认 bonding 只会以单口回复 ARP&#xff0c;另一台交换机收不到 ARP Reply。本文在 Linux bonding 驱动中增加参数 arp_broadcast_mode&#xff0c;当开启时对 ARP 包临时切换到 广播模式&#xff0c;实现双口同时发 ARP Reply。文内提…

网页连接摄像头

摄像机处理 <!-- camera_solve.html --> <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>…

FPGA雷达信号处理之:自适应门限阈值

一、原理 参考这个博主&#xff0c;讲的很仔细&#xff1a;基于脉冲功率的雷达脉冲参数检测原理详解 二、FPGA实现 使用system generator搭建算法模型如下&#xff1a; 在这里&#xff0c;滤波器窗长度为8&#xff0c;原博主设置为50效果更好&#xff0c;门限公式如下&#xf…

Vue 中实现选中文本弹出弹窗的完整指南

在现代 Web 应用中&#xff0c;选中文本后显示相关操作或信息是一种常见的交互模式。本文将详细介绍如何在 Vue 中实现选中文本后弹出弹窗的功能&#xff0c;包括其工作原理、多种实现方式以及实际项目中的应用示例。 一、实现原理 1. 文本选中检测机制 浏览器提供了 Select…

第4节-排序和限制-FETCH

摘要: 在本教程中&#xff0c;你将学习如何使用 PostgreSQL 的 FETCH 子句从查询中检索部分行。 PostgreSQL FETCH 简介 在 PostgreSQL 中&#xff0c;OFFSET 子句的作用类似于 LIMIT 子句。FETCH 子句允许你限制查询返回的行数。 LIMIT 子句并非 SQL 标准的一部分。不过&#…

洛谷 P2680 [NOIP 2015 提高组] 运输计划(二分答案 + 树上差分)

题目链接题目概括与评价 很经典&#xff0c;突破口藏的很深&#xff0c;求最小值这里&#xff0c;是问题切入点&#xff0c;想到用二分答案&#xff0c;然后思考怎么写 f_check 函数。二分答案树上差分。代码 #include <iostream> #include <vector> #include <…

接力邓承浩,姜海荣能讲好深蓝汽车新故事吗?

出品 | 何玺排版 | 叶媛深蓝汽车迎来新话事人。9月5日&#xff0c;新央企长安汽车旗下品牌深蓝汽车传出新的人事调整。多家业内媒体报道称&#xff0c;荣耀前中国区CMO姜海荣已正式加入长安汽车&#xff0c;并出任旗下深蓝汽车CEO一职。原CEO邓承浩则升任深蓝汽车董事长&#x…