SpringBoot原理分析-1
SpringBoot原理分析
作为一个javaer,和boot打交道是很常见的吧。熟悉boot的人都会知道,启动一个springboot应用,就是用鼠标点一下启动main方法,然后等着就行了。我们来看看这个main里面。
@SpringBootApplication
public class ExampleApplication {public static void main(String[] args) {SpringApplication.run(ExampleApplication.class, args);}
}
这个类很简单吧,有三个注意点。
- ExampleApplication就是类名,为了规范起见,这个类名一般都是xxxApplication。
- 有一个注解@SpringBootApplication。
- 然后就一个main方法,里面使用了SpringApplication的静态方法run(),传进去了俩参数。
这就神奇地启动起来了,为什么呢?
分析的版本:SpringBoot 2.7.18
需要结合以前用xml文件来配置Spring容器的形式来对比Boot用注解的形式
1.注解&自动配置
目前只知道注解的作用即可,至于这些注解是怎么起作用的,见后续…
@SpringBootApplication
这一节来详细聊一聊这个注解。@SpringBootApplication 是 Spring Boot 框架中的一个核心注解,用于简化 Spring Boot 应用的配置和启动
它的作用
@SpringBootApplication标注在应用的主类上,用于启动 Spring Boot 应用。- 它启用了 Spring Boot 的自动配置机制,根据项目的依赖自动配置 Spring 应用。
- 组件扫描:它启用了组件扫描,自动发现并注册带有
@Component、@Service、@Repository、@Controller等注解的类。 - 配置类:它标记该类为 Spring 的配置类,相当于
@Configuration注解。
点进去看看,该注解的结构如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited // 四个元注解
@SpringBootConfiguration
@EnableAutoConfiguration //启用SpringBoot的自动配置机制。SpringBoot会根据类路径中的依赖自动配置应用。例如,如果类路径中有spring-boot-starter-web,SpringBoot会自动配置Tomcat和SpringMVC。@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) // 启用组件扫描,并排除一些特定的过滤器。默认是注解标注的类所在包及其子包。实际上是不是就是主启动类所在包及其子包!!!!!
public @interface SpringBootApplication {
..............
}// 发现这是一个组合注解
@SpringBootConfiguration 注解:主要作用是标记一个类为 Spring Boot 的配置类与 @Configuration 类似,但它专门用于 Spring Boot 应用。这个注解和@ComponentScan注解结合到一起,达成了如下效果。(左边是xml文件配置形式,右边是SpringBoot注解的形式),这俩注解在一起,就是扫描主启动类所在包及其子包下的被@Controller、@Service、…标注的类,将他们归到Spring容器里面去。

@EnableAutoConfiguration
@EnableAutoConfiguration注解: 这个注解不得了啊。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) // 这里。
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};}
发现@Import注解。这个注解的作用是干啥的?这里给出GPT的回答:@Import 是 Spring 框架提供的一个注解,用于将一个或多个配置类(@Configuration 类)或组件类导入到当前的 Spring 应用上下文中。它可以用来显式地引入其他配置类或 Bean 定义,从而实现模块化配置和代码复用。
这里有一个非常重要的东西,那就是当前的Spring上下文,也就是主启动类所在包及其子包,@Import(AutoConfigurationImportSelector.class)这句话的意思是将SpringBoot官方写的AutoConfigurationImportSelector类导入到当前Spring上下文中,在当前Spring上下文注册这样一个bean。
AutoConfigurationImportSelector探究
public interface ImportSelector {String[] selectImports(AnnotationMetadata importingClassMetadata);
}
// 实现了DeferredImportSelector接口,DeferredImportSelector实现了ImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {...........AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); // 1.进去return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}// 2.这个方法protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);// 3.进入这里List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);...........}// 4. 3调用的这个方法protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = new ArrayList<>(// 5. 继续往下SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations,"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}// 6. 5处调用的方法public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {...... // loadSpringFactoriesreturn loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}// 7// 最终可以在loadSpringFactories方法里面看到这样一行代码//Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);// public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";// 结合官方给的解释The location to look for factories. Can be present in multiple JAR files. 寻找工厂的位置。可以存在于多个 JAR 文件中。
}
结合idea打断点调试:我们发现getCandidateConfigurations扫描到了引入的所有jar包的META-INF/spring.factories,共有156个xxxAutoConfigure类。但是这些都会用到吗,别忘了,SpringBoot有个非常强大的特点:那就是导入场景、对应的场景才会生效!!

继续往下走,请看下图:(发现只有50个了,例如上图里面的amqp,由于项目中没有用到,故在这里就没有了,经过了filter过滤)

以RabbitMq自动配置为例
@AutoConfiguration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class }) // 这两个类存在时才生效,项目里面没导入相关jar包,故RabbitAutoConfiguration不会被导入Spring容器生效,下面就来说这个注解
@EnableConfigurationProperties(RabbitProperties.class)
@Import({ RabbitAnnotationDrivenConfiguration.class, RabbitStreamConfiguration.class })
public class RabbitAutoConfiguration {................
}
@ConditionalOnClass
先看看其源码
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class) // 这里***
public @interface ConditionalOnClass {Class<?>[] value() default {};String[] name() default {};
}
@ConditionalOnClass注解的作用是当项目中存在某个类时才会使标有该注解的类或方法生效;
先看我们的主类**【1. 此时,没有引入test.demo.test.list.Student所在的maven依赖】**
/* 下面是这俩类
public class Cat {private Integer id;private String name;
}
public class Dog {private Integer id;private String name;
}*/@SpringBootApplication
@MapperScan("com.feng.tackle.dao")
public class DateApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(DateApplication.class, args);ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();Iterator<String> iterator = beanFactory.getBeanNamesIterator();while (iterator.hasNext()) {String name = iterator.next();if ( name.equals("dog01") || name.equals("cat01") ) System.out.println(name); // 看看有没有这两个名字的bean}}
}
// 最后的输出结果
/*
cat01
*/
在配置类中,我们这样做
@Configuration
public class ConditionTestConfig {@ConditionalOnClass(name = "test.demo.test.list.Student") // 类路径有这个类,就往容器中放入该bean@Beanpublic Dog dog01() {return new Dog(2, "汪汪汪");}@ConditionalOnMissingClass("test.demo.test.list.Student") // 类路径没有这个类,就往容器中放入该bean@Beanpublic Cat cat01() {return new Cat(1, "喵喵喵");}
}
main最后的输出结果是cat01。"test.demo.test.list.Student"是另一个maven项目里面的类。

【2. 项目中引入Student所在的maven】
<dependency><groupId>com.feng.test</groupId><artifactId>test-demo</artifactId><version>1.0-SNAPSHOT</version>
</dependency>
再次启动main,输出结果dog01

通过这个例子,我们可以知道SpringBoot自动配置,导入具体starter,对应的场景才会生效。【由于没有导入MQ的starter,故此配置类不会生效】

总结
**自动配置: **
以spring-boot-starter-web为例子,引入该启动器,他的父级pom里面有spring-boot-starter,spring-boot-starter的父级pom有spring-boot-autoconfigure。
spring-boot-autoconfigure里面有Spring官方定义的所有场景。

@EnableAutoConfiguration注解:这是自动配置的入口,通常由@SpringBootApplication注解组合引入。spring.factories文件:Spring Boot 通过META-INF/spring.factories文件加载自动配置类。- 条件化配置:通过
@Conditional系列注解(如@ConditionalOnClass、@ConditionalOnMissingBean等)实现按需加载配置。
自动配置的流程:
- 加载自动配置类
@SpringBootApplication注解:该注解是一个组合注解,包含了@EnableAutoConfiguration,用于启用自动配置。@EnableAutoConfiguration的作用:该注解会通过SpringFactoriesLoader加载META-INF/spring.factories文件中定义的自动配置类。
- 条件化配置
自动配置类通常使用 @Conditional 系列注解来控制是否生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {// 自动配置逻辑
}
//如果类路径中存在 DataSource 和 EmbeddedDatabaseType,且容器中没有 ConnectionFactory Bean,则自动配置 DataSource。
- 加载配置属性
@EnableConfigurationProperties:自动配置类通常会通过该注解加载配置属性。application.properties或application.yml:Spring Boot 会读取这些配置文件中的属性,并将其绑定到对应的配置类中。
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {private String url;private String username;private String password;// getters and setters
}
- 注册bean
- 自动配置类通过
@Bean方法向容器中注册 Bean。 - 这些 Bean 通常是框架的核心组件,如
DataSource、DispatcherServlet、SecurityFilterChain等。
2. 启动过程
SpringApplication.run(ExampleApplication.class, args);这一行代码做了啥?这才是重点!
从run开始看,一层一层往下面点进去
// 1.
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { // 会返回一个正在运行的Spring容器return run(new Class<?>[] { primarySource }, args); // 调用重载的run方法
}
// 2.
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); // 先调用该构造方法,然后再调用run方法,将程序参数传进去
}
// 3.
public SpringApplication(Class<?>... primarySources) {this(null, primarySources); //primarySource 是传入的主配置类(通常带有 @SpringBootApplication 注解的类),Spring Boot 会将其作为配置源。
}// 4. [构造方法] 构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {........ // 见下一节构造方法
}
先调用该构造方法,然后再调用run方法
①构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader; // null的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(); // 六、通过堆栈信息推断出主类(即 main 方法所在的类)。
}
1.推断应用类型
WebApplicationType.deduceFromClasspath()方法会根据类路径中是否存在特定的类来推断应用类型。- 可能的类型包括:
WebApplicationType.SERVLET:基于 Servlet 的 Web 应用(如 Spring MVC)。WebApplicationType.REACTIVE:基于 Reactive 的 Web 应用(如 Spring WebFlux)。WebApplicationType.NONE:非 Web 应用。
2.加载并初始化 BootstrapRegistryInitializer 实例
分析一下核心方法getSpringFactoriesInstances,下面两个都会调用这个。
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;
}// SpringFactoriesLoader.loadFactoryNames(type, classLoader) 到这儿来了
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoaderToUse == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}//loadSpringFactories(classLoaderToUse)
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {// static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap<>();// 从缓存map中拿到对应classLoader的map,如果该classLoader已经存在了,就不用走下面的了Map<String, List<String>> result = cache.get(classLoader);if (result != null) {return result;}result = new HashMap<>();try {/*public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";结合官方给的解释The location to look for factories. Can be present in multiple JAR files. 寻找工厂的位置。可以存在于多个 JAR 文件中。*/Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);..............return result;
}
可以看到这里,在第一章《注解&自动配置》也出现了这个,如今在SpringApplication的构造方法,底层也调用到了这里。二者有什么区别或者联系呢?
SpringFactoriesLoader.loadFactoryNames是Spring Boot 提供的工具方法,用于从 META-INF/spring.factories 文件中加载指定类型的配置类。
两者都依赖于 META-INF/spring.factories 文件,该文件是 Spring Boot 自动配置和扩展机制的核心配置文件。两者都通过类路径扫描,加载所有 META-INF/spring.factories 文件,并解析出指定类型的配置类。
(1)调用位置
AutoConfigurationImportSelector:- 位于
org.springframework.boot.autoconfigure包中。 - 是 Spring Boot 自动配置的核心组件之一,负责加载自动配置类。
- 在 Spring 容器的配置类解析阶段被调用(具体是在
@EnableAutoConfiguration注解的处理过程中)。
- 位于
SpringApplication:- 位于
org.springframework.boot包中。 - 是 Spring Boot 应用的启动类,负责初始化应用上下文、加载配置等。
- 在应用启动时被调用。
- 位于
(2)加载的配置类型
AutoConfigurationImportSelector:- 主要加载
META-INF/spring.factories文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration键下的自动配置类。 - 这些配置类用于实现 Spring Boot 的自动配置功能(如
DataSourceAutoConfiguration、WebMvcAutoConfiguration等)。
- 主要加载
SpringApplication:- 加载多种类型的配置类,包括:
ApplicationContextInitializerApplicationListenerBootstrapRegistryInitializer
- 这些配置类用于初始化应用上下文、监听应用事件等。
- 加载多种类型的配置类,包括:
(3)调用时机
AutoConfigurationImportSelector:- 在 Spring 容器解析配置类时调用(具体是在
ConfigurationClassPostProcessor处理@Configuration类时)。 - 属于 Spring 容器初始化的早期阶段。
- 在 Spring 容器解析配置类时调用(具体是在
SpringApplication:- 在应用启动时调用(具体是在
SpringApplication的构造方法或run方法中)。 - 属于应用启动的早期阶段。
- 在应用启动时调用(具体是在
(4)返回值的使用
AutoConfigurationImportSelector:- 返回的自动配置类会被 Spring 容器加载并处理,最终生成相应的 Bean 定义。
- 这些配置类通常包含
@Configuration注解和@Conditional注解,用于按需加载 Bean。
SpringApplication:- 返回的配置类会被直接实例化并注册到应用中。
- 例如,
ApplicationContextInitializer会被调用以初始化应用上下文,ApplicationListener会被注册以监听应用事件。
3.加载并设置 ApplicationContextInitializer 实例
同2
4.加载并设置 ApplicationListener 实例
同2
总结
BootstrapRegistryInitializer:用于应用启动的最早阶段,初始化引导阶段的组件。ApplicationContextInitializer:用于在ApplicationContext创建之后、刷新之前,对上下文进行自定义初始化。ApplicationListener:用于监听应用生命周期中的事件,并在特定阶段执行逻辑。
这三者共同扩展了 Spring Boot 应用的启动过程,提供了灵活的扩展点,可以满足不同场景下的需求。
5.三者的实现
分别编写实现类
public class MyBootstrapInit implements BootstrapRegistryInitializer {@Overridepublic void initialize(BootstrapRegistry registry) {System.out.println("【MyBootstrapInit】--------------方法执行了");}
}public class MyApplicationContextInit implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println("【MyApplicationContextInit】------------" + applicationContext.getApplicationName());}
}public class MyContextListener implements ApplicationListener<ApplicationStartedEvent> { // 该监听器对此事件感兴趣@Overridepublic void onApplicationEvent(ApplicationStartedEvent event) {System.out.println("【MyContextListener】--监听器--" + event.getSource());}
}
然后在resource目录下面创建META-INF,在其中的spring.factories中
org.springframework.boot.BootstrapRegistryInitializer=com.feng.tackle.config.source.MyBootstrapInit
org.springframework.context.ApplicationContextInitializer=com.feng.tackle.config.source.MyApplicationContextInit
org.springframework.context.ApplicationListener=com.feng.tackle.config.source.MyContextListener
启动应用:

疑问? 我可以在这三者的实现类上面加@Configuration注解,不要spring.factories,可以实现类似效果吗?
答案是,只有ApplicationListener可以。为什么?请看下面的run方法里面
②run
public ConfigurableApplicationContext run(String... args) {// 记录应用启动的开始时间,用于后续计算启动耗时。long startTime = System.nanoTime(); //创建一个 BootstrapContext,用于在应用启动的早期阶段提供一些基础设施支持(如环境配置、属性源等)================DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 设置系统属性 java.awt.headless,确保应用在没有图形界面环境(如服务器)中也能正常运行configureHeadlessProperty();/*获取所有 SpringApplicationRunListener 实例,用于监听应用启动的各个阶段。调用 listeners.starting(),通知监听器应用正在启动。*/SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 加载和配置应用的环境(Environment),包括配置文件(如 application.properties 或 application.yml)、命令行参数等。ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 打印 Spring Boot 的启动 Banner(默认或自定义)。Banner printedBanner = printBanner(environment);// 根据应用类型(Servlet、Reactive 等)创建相应的 ApplicationContext。context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 准备应用上下文prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 调用 AbstractApplicationContext.refresh() 方法,完成 Bean 的实例化、依赖注入和初始化。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);// 执行所有 ApplicationRunner 和 CommandLineRunner 的实现类,用于在应用启动后执行自定义逻辑。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;
}
这个run这里分析得不够深入。受篇幅影响,在后续文章中再来分析。
end. 参考
- 尚硅谷雷丰阳老师的课
相关文章:
SpringBoot原理分析-1
SpringBoot原理分析 作为一个javaer,和boot打交道是很常见的吧。熟悉boot的人都会知道,启动一个springboot应用,就是用鼠标点一下启动main方法,然后等着就行了。我们来看看这个main里面。 SpringBootApplication public class E…...
HCIA-Access V2.5_7_5_XG(S)- GPON网络演进为XG(S)-PON网络
目前由于10 GPON ONU数量并没有得到大规模爆发,所以直接新建ODN网络成本相对较高,所以可以采用复用ODN的方案。 XG(S)-PON可以与GPON共享ODN 前面也介绍过GPON和10G GPON使用的波长,我们来回顾一下,在GPON网络中上行采用1310纳米波长,下行采用1490纳米的波长,而10G GPON…...
GPU算力平台的应用之任意门:任意穿搭匹配模型的应用教程
大家好,今天给大家介绍一下:GPU算力平台的应用之任意门:任意穿搭匹配模型的应用教程。 文章目录 一、GPU算力平台概述人工智能智能发展为什么需要GPU算力平台 二、注册与登录账号注册流程 三、平台的应用之Anydoor应用启动器选择Anydoor的应用场景Anydoo…...
如何利用人工智能算法优化知识分类和标签?
如何利用人工智能算法优化知识分类和标签? 聚类算法 原理与应用: 聚类算法是一种无监督学习算法,它可以根据数据的相似性将知识内容自动划分成不同的类别。例如,在文档知识库中,通过对文档内容的词向量表示应用 K -…...
Windows 11 系统中npm-cache优化
在 Windows 11 系统中,C:\Users\K\AppData\Local\npm-cache 文件夹是 npm(Node Package Manager) 用于缓存已下载的包的目录。缓存的存在可以加快包的安装速度,因为当再次安装相同的包时,npm 可以直接从缓存中获取&…...
Flink使用
Window下启动支持 下载或复制老版本的放在bin目录下即可; flink.bat echo off setlocalSET bin%~dp0 SET FLINK_HOME%bin%.. SET FLINK_LIB_DIR%FLINK_HOME%\lib SET FLINK_PLUGINS_DIR%FLINK_HOME%\pluginsSET JVM_ARGS-Xmx512mSET FLINK_JM_CLASSPATH%FLINK_LI…...
简易屏幕共享工具-基于WebSocket
前面写了两个简单的屏幕共享工具,不过那只是为了验证通过截屏的方式是否可行,因为通常手动截屏的频率很低,而对于视频来说它的帧率要求就很高了,至少要一秒30帧率左右。所以,经过实际的截屏工具验证,我了解…...
Redis——主从复制模式
文章目录 1. 引入2. 主从复制模式2.1 概念2.2 配置2.3 原理2.3.1 建立连接阶段2.3.2 命令传播阶段2.3.3 心跳检测机制2.3.4 部分重同步机制(1) 主节点通过 复制积压缓冲区 记录写命令(2) 主节点通过 复制偏移量 判断从节点是否满足执行部分重同步的条件(3) 执行部分重同步操作 …...
简历_熟悉缓存高并发场景处理方法,如缓存穿透、缓存击穿、缓存雪崩
系列博客目录 文章目录 系列博客目录1.缓存穿透总结 2.缓存雪崩3.缓存击穿代码总结 1.缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。 常见的解决方案有两种: 缓存空对…...
阿里云电商平台用户行为分析与人群画像系统设计与实现
通过在阿里云(https://baike.baidu.com/item/%E9%98%BF%E9%87%8C%E4%BA%91/297128)上构建包含数据源层、数据存储层、数据处理层、数据分析层和数据应用层的系统架构,并设计合理的数据模型、ETL流程、数据质量与性能监控机制以及安全与合规性…...
Go语言的 的输入/输出流(I/O Streams)核心知识
Go语言的输入/输出流(I/O Streams)核心知识 前言 Go语言是一种现代编程语言,因其高效性、简洁性及强大的并发支持而受到开发者的喜爱。在开发应用程序时,输入/输出(I/O)操作是一个不可或缺的部分。无论是…...
57.在 Vue 3 中使用 OpenLayers 点击选择 Feature 设置特定颜色
在 Web 开发中,地图应用是非常常见的需求,而 OpenLayers 是一个非常强大的地图库,它提供了丰富的地图操作功能。今天,我们将一起学习如何在 Vue 3 中结合 OpenLayers 使用点击事件来选择地图上的 Feature,并设置特定的…...
数据结构C语言描述8(图文结合)--哈希、哈希冲突、开放地址法、链地址法等实现
前言 这个专栏将会用纯C实现常用的数据结构和简单的算法;有C基础即可跟着学习,代码均可运行;准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言…...
自动化立体库安全使用管理制度完整版
导语 大家好,我是社长,老K。专注分享智能制造和智能仓储物流等内容。欢迎大家到本文底部评论区留言。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料,请球友到知识星球【智能仓储物流技术研习社】自行下载。 以下是《…...
云打印之拼多多打印组件交互协议
拼多多打印组件交互协议相关介绍如下: 1、打印组件下载地址 http://meta.pinduoduo.com/api/one/app/v1/lateststable?appIdcom.xunmeng.pddprint&platformwindows&subTypemain 2、socket连接端口 如果是http的话,端口是5000 socket new …...
TCP 演进之路:软硬件跷跷板与新征程
今天依旧是与 TCP 相关的一个短评。 先看软硬件间的胶着。晶体管诞生以来,硬件一直在突飞猛进发展,后来这个事被摩尔定律正则化,人们开始可以预测未来,但即便如此,软件依然跟不上来,不过几年,老…...
React最小状态管理Jotai
Jotai 状态管理 1. 简介 Jotai 是一个基于原子 atom 概念的 React 状态管理库,它提供了简单且灵活的方式来管理应用状态, 而且非常轻量, 大厂用的非常多。 JotaiRedux适合单个页面,多次用到的属性适合全局公共属性超级轻量(与use…...
计算机网络 —— 网络编程(TCP)
计算机网络 —— 网络编程(TCP) TCP和UDP的区别TCP (Transmission Control Protocol)UDP (User Datagram Protocol) 前期准备listen (服务端)函数原型返回值使用示例注意事项 accpect (服务端)函数原型返回…...
字玩FontPlayer开发笔记4 性能优化 首屏加载时间优化
字玩FontPlayer开发笔记4 性能优化 首屏加载时间优化 字玩FontPlayer是笔者开源的一款字体设计工具,使用Vue3 ElementUI开发,源代码: github: https://github.com/HiToysMaker/fontplayer gitee: https://gitee.com/toysmaker/fontplayer …...
RabbitMQ案例
1. 导入依赖 <!--AMQP依赖,包含RabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency> 发送消息 注入RabbitTemplate Autowired RabbitT…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
