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
:- 加载多种类型的配置类,包括:
ApplicationContextInitializer
ApplicationListener
BootstrapRegistryInitializer
- 这些配置类用于初始化应用上下文、监听应用事件等。
- 加载多种类型的配置类,包括:
(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…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...