当前位置: 首页 > news >正文

spring(15) SpringBoot启动过程

目录

    • 一、过程简介
    • 二、过程流程图
    • 三、源码分析
      • 1、运行 SpringApplication.run() 方法
      • 2、确定应用程序类型
      • 3、加载所有的初始化器
      • 4、加载所有的监听器
      • 5、设置程序运行的主类
      • 6、开启计时器
      • 7、将 java.awt.headless 设置为 true
      • 8、获取并启用监听器
      • 9、设置应用程序参数
      • 10、准备环境变量
      • 11、忽略 Bean 信息
      • 12、打印 banner 信息
      • 13、创建应用程序的上下文
      • 14、实例化异常报告器
      • 15、准备上下文环境
        • 15.1、实例化单例的 beanName 生成器
        • 15.2、执行初始化方法
        • 15.3、将启动参数注册到容器中
      • 16、refresh 刷新上下文(实例化 Bean)
        • 16.1、refresh() 方法内容
        • 16.2、Bean 对象的创建
      • 17、刷新上下文后置处理
      • 18、结束计时器
      • 19、发布上下文准备就绪事件
      • 20、执行自定义的 run 方法

最好的学习方式就是带着问题学习,在分析 SpringBoot 的启动过程前,先问大家两个问题:

  1. 在启动过程中,SpringBoot 是在哪一步实例化 Bean 的?

    答案:在本文的第 16 步 refresh() 刷新上下文的时候实例化的。

  2. ApplicationContext 作为一个 IOC 容器,底层是通过什么方式来存储实例化好的 Bean 呢?

    答案:ApplicationContext 是先使用 Set 集合将 BeanDefinition 存储起来,然后再将不是抽象的、单例的、非懒加载的类进行实例化,然后存放到 Map 集合中统一管理。

文章中使用的源码版本:

  • spring-boot: 2.2.x
  • spring-framework: 5.2.x

话不多说,下面就让我们开始了解 SpringBoot 的启动过程吧。


一、过程简介

首先,SpringBoot 启动的时候,会构造一个 SpringApplication 的实例,构造时会进行初始化的工作。初始化的时候会做以下几件事情:

  1. 把参数 sources 设置到 SpringApplication 属性中,这个 sources 可以是任何类型的参数;
  2. 判断是否是 web 程序,并设置到 webEnvironmentboolean 属性中;
  3. 创建并初始化 ApplicationInitializer,设置到 initializers 属性中;
  4. 创建并初始化 ApplicationListener,设置到 listeners 属性中;
  5. 初始化主类 mainApplicationClass

其次,SpringApplication 构造完成之后调用 run 方法,启动 SpringApplication。run 方法执行的时候会做以下几件事:

  1. 构造一个 StopWatch 计时器,用来记录 SpringBoot 的启动时间;
  2. 初始化监听器,获取 SpringApplicationRunListeners 并启动监听,用于监听 run 方法的执行。
  3. 创建并初始化 ApplicationArguments,获取 run 方法传递的 args 参数。
  4. 创建并初始化 ConfigurableEnvironment(环境配置)。封装 main 方法的参数,初始化参数,写入到 Environment 中,发布 ApplicationEnvironmentPreparedEvent(环境事件),做一些绑定后返回 Environment
  5. 打印 banner 和版本。
  6. 构造 Spring 容器(ApplicationContext)上下文。先填充 Environment 环境和设置的参数,如果 application 有设置 beanNameGenerator(bean)、resourceLoader(加载器)就将其注入到上下文中,调用初始化的切面,发布 ApplicationContextInitializedEvent(上下文初始化)时间。
  7. SpringApplicationRunListeners 发布 finish 事件。
  8. StopWatch 计时器停止计时,日志打印总共启动的时间。
  9. 发布 SpringBoot 程序已启动事件(started())。
  10. 调用 ApplicationRunnerCommandLineRunner
  11. 最后发布就绪事件 ApplicationReadyEvent,标志着 SpringBoot 可以处理接收的请求了(running())。

二、过程流程图

在这里插入图片描述

由此看来,SpringBoot 的启动过程还是挺多的,下面我们结合源码,详细分析讲解启动过程中的步骤。

三、源码分析

1、运行 SpringApplication.run() 方法

可以肯定的是,所有的标准 SpringBoot 应用都是从 run 方法开始的。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {// 启动应用SpringApplication.run(SpringbootDemoApplication.class, args);}}

进入 run 方法后,会 new 一个 SpringApplication 上下文对象,创建这个对象的构造方法做了一些准备工作,第 2 ~ 5 步就是构造函数里面做的事情。

/*** Static helper that can be used to run a {@link SpringApplication} from the* specified source using default settings.* @param primarySource the primary source to load* @param args the application arguments (usually passed from a Java main method)* @return the running {@link ApplicationContext}*/
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] { primarySource }, args);
}

另外补充一下,SpringBoot 除了 SpringApplication.run() 方法启动之外,还可以通过 AnnotationConfigApplicationContext 指定配置类启动,这里就不展开说明了。

2、确定应用程序类型

在 SpringApplication 的构造方法内,首先会通过 WebApplicationType.deduceFromClasspath(); 方法判断当前应用程序的容器,默认使用的是 Servlet 容器,除了 Servlet 之外,还有 NONE 和 REACTIVE(响应式编程)。

在这里插入图片描述

/*** 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();
}

3、加载所有的初始化器

这里加载的初始化器是 SpringBoot 自带的初始化器,从 META-INFO/spring.factories 配置文件中加载的,那么这个文件在哪呢?自带的有2个,分别在源码的 jar 包的 spring-boot-autoconfigure 项目和 spring-boot 项目里面各有一个:

在这里插入图片描述

spring.factories 文件里面,可以看到开头是 org.springframework.context.ApplicationContextInitializer 接口就是初始化器了:

在这里插入图片描述

当然,我们也可以自己实现一个自定义的初始化器:实现 ApplicationContextInitializer 接口即可。

MyApplicationContextInitializer.java

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;/*** 自定义初始化器*/
public class MyApplicationContextInitializer implements ApplicationContextInitializer {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println("MyApplicationContextInitializer.initialize()");}
}

在 resources 目录下添加 META-INF/spring.factories 配置文件,目录如下,将自定义的初始化器注册进去:

org.springframework.context.ApplicationContextInitializer=\
com.demo.application.MyApplicationContextInitializer

在这里插入图片描述

启动 SpringBoot 后,就可以看到控制台打印的内容了,在这里我们可以很直观地看到它地执行顺序,是在打印 banner 的后面执行的:

在这里插入图片描述

4、加载所有的监听器

加载监听器也是从 META-INF/spring.factories 配置文件中加载的,与初始化不同的是,监听器的加载是为了实现 ApplicationListener 接口的类。

在这里插入图片描述

自定义监听器也跟自定义初始化器一样,这里不再举例。

5、设置程序运行的主类

deduceMainApplicationClass(); 这个方法仅仅是找到 main 方法所在的类,为后面的扫包做准备,deduce 是推断的意思,所以准确的说,这个方法作用是推断出主方法所在的类。

在这里插入图片描述

6、开启计时器

程序运行到这里,就已经进入了 run 方法的主体了,第一步调用的 run 方法是静态方法,那个时候还没实例化 SpringApplication 对象,现在调用的 run 方法是非静态的,是需要实例化后才可以调用的,进来后首先会开启计时器,这个计时器有什么作用呢?顾名思义,就是用来记录 SpringBoot 启动时长的,核心代码如下:

// 实例化计时器
StopWatch stopWatch = new StopWatch();
// 开始计时
stopWatch.start();

run 方法代码段截图:

在这里插入图片描述

7、将 java.awt.headless 设置为 true

这里将 java.awt.headless 设置为 true,表示运行在服务器端,在没有显示和鼠标键盘的模式下照样可以工作,模拟输入输出设备功能。

做了这样的操作后,SpringBoot 想干什么呢?其实是像设置该应用程序,即使没有检测到显示器,也允许其启动,对于服务器来说,是不需要显示器的,所以要这样设置。

方法主体如下:

private void configureHeadlessProperty() {System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

通过方法可以看到,setProperty() 方法里面有有个 getProperty(); 这不是多此一举吗?其实 getProperty() 方法里面有2个参数,第一个 key 值,第二个默认值,意思是通过 key 值查找属性值,如果属性值为空,则返回默认值 true;保证了一定有值的情况。

8、获取并启用监听器

这一步,通过监听器来实现初始化的基本操作,这一步做了2件事:

1)创建所有 Spring 运行监听器,并发布应用启动事件。

2)启用监听器。

在这里插入图片描述

9、设置应用程序参数

将执行 run 方法时传入的参数封装成一个对象。

在这里插入图片描述

这里只是将参数封装成对象,没啥好说的,对象的构造函数如下:

public DefaultApplicationArguments(String... args) {Assert.notNull(args, "Args must not be null");this.source = new Source(args);this.args = args;
}

这里的 args 参数其实就是 main 方法里面执行静态 run 方法时传入的参数。

在这里插入图片描述

10、准备环境变量

准备环境变量,包括系统属性和用户配置的属性,执行的代码块在 preparedEnvironment 方法内。

在这里插入图片描述

打了断点之后可以看到,它将 Maven 和系统的环境变量都加载进来了。

在这里插入图片描述

11、忽略 Bean 信息

configureIgnoreBeanInfo() 这个方法是将 spring.beaninfo.ignore 的默认值设置为 true,意思是忽略 Java Bean 的信息解析:

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

当然也可以在配置文件中添加以下配置来设为 false。

spring.beaninfo.ignore=false

当 spring.beaninfo.ignore 配置被设置为 false 时,Spring 框架会解析 Java Bean 的信息,包括属性、方法、事件等,以便在运行时进行操作。

需要注意的是,在现在的 Java 环境中,Java Bean 的信息解析通常不再需要,而且会对性能产生负面影响。因此,大多数形况下,无需关注或更改该配置。

12、打印 banner 信息

显而易见,这个流程就是用来打印控制台那个很大的 Spring 的 banner 图案,就是下面这个东西:

在这里插入图片描述

那他在哪里打印的呢?是在 SpringBootBanner.java 里面打印的,这个类实现了 Banner 接口,而且 banner 信息时直接在代码里面写死的。

在这里插入图片描述

13、创建应用程序的上下文

实例化 ApplicationContext(应用程序的上下文),调用 createApplicationContext() 方法,这里就使用反射创建对象,没什么好说的。

在这里插入图片描述

14、实例化异常报告器

异常报告器时用来捕获全局异常使用的,当 SpringBoot 应用程序在发生异常时,异常报告器会将其捕捉并作响应处理,在 spring.factories 文件里配置了默认的异常报告器:

在这里插入图片描述

需要注意的是,这个异常报告器只会捕获启动过程抛出的异常,如果是在启动完成后,在用户请求时报错,异常捕获器不会捕获请求中出现的异常。

在这里插入图片描述

了解了远离了,接下来我们自己配置一个异常报告器试试。

创建 MyExceptionReporter.java 类,继承 SpringBootExceptionReporter 接口。

import org.springframework.boot.SpringBootExceptionReporter;
import org.springframework.context.ConfigurableApplicationContext;/*** 自定义异常报告器*/
public class MyExceptionReporter implements SpringBootExceptionReporter {private ConfigurableApplicationContext context;// 必须要有一个有参构造函数,否则启动会报错MyExceptionReporter(ConfigurableApplicationContext context) {this.context = context;}@Overridepublic boolean reportException(Throwable failure) {System.out.println("MyExceptionReporter.reportException() is called.");failure.printStackTrace();// 返回false会打印详细 SpringBoot 报错信息,返回true则纸打印异常信息。return false;}
}

在 spring.factories 文件中注册异常报告器。

# Error Reporters 异常报告器
org.springframework.boot.SpringBootExceptionReporter=\
com.demo.application.MyExceptionReporter

在这里插入图片描述

然后我们在 application.yml 中把端口设置为一个很大的值(端口的最大值为65535),我们设置为5个8:

server:port: 88888

启动后,控制台打印截图如下:

在这里插入图片描述

15、准备上下文环境

这里准备的上下文环境是为了下一步刷新做准备的, 里面还做了一些额外的事情:

在这里插入图片描述

15.1、实例化单例的 beanName 生成器

在 postProcessApplicationContext(context); 方法里面。使用单例模式创建了 BeanNameGenerator 对象,其实就是 beanName 生成器,用来生成 bean 对象的名称。

15.2、执行初始化方法

初始化方法有哪些呢?还记得第3步里面加载的初始化器吗?其实是执行第3步加载出来的所有初始化器,实现了 ApplicationContextInitializer 接口的类。

15.3、将启动参数注册到容器中

这里将启动参数以单例的模式注册到容器中,是为了以后方便拿来使用,参数的 beanName 为:springApplicationArguments。

16、refresh 刷新上下文(实例化 Bean)

刷新上下文就到了 Spring 的范畴了,这里进行了自动装配和启动 tomcat,以及其他 Spring 自带的机制。这里我们主要看一下 refresh() 方法包含了哪些内容,以及 Bean 对象的创建具体是如何进行的?

16.1、refresh() 方法内容

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {//为容器初始化做准备prepareRefresh();// 解析xml和注解ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 给BeanFacory设置属性值以及添加一些处理器,即准备Spring的上下文环境prepareBeanFactory(beanFactory);try {// 由子类实现对BeanFacoty的一些后置处理postProcessBeanFactory(beanFactory);/** BeanDefinitionRegistryPostProcessor* BeanFactoryPostProcessor* 完成对这两个接口的调用*/invokeBeanFactoryPostProcessors(beanFactory);/** 把实现了BeanPostProcessor接口的类实例化,并且加入到BeanFactory中*/registerBeanPostProcessors(beanFactory);/** 国际化*/initMessageSource();//初始化事件管理类initApplicationEventMulticaster();//这个方法着重理解模板设计模式,因为在springboot中,这个方法是用来做内嵌tomcat启动的onRefresh();/** 往事件管理类中注册事件类*/registerListeners();/** 1、bean实例化过程* 2、依赖注入* 3、注解支持* 4、BeanPostProcessor的执行* 5、Aop的入口*/finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();} finally {resetCommonCaches();}}
}

16.2、Bean 对象的创建

当前面的准备工作做好后,就开始初始化 Bean 实例了,也就是 finishBeanFactoryInitialization 方法所作的事。不过这里可不是根据 BeanDefinition 去 new 一个对象就完了,它包含了以下几个工作:

  • 初始化实例。
  • 解析 @PostConstruct、@PreDestroy、@Resource、@Autowired、@Value 等注解。
  • 依赖注入。
  • 调用 BeanPostProcessor 方法。
  • AOP 入口。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {......//重点看这个方法// Instantiate all remaining (non-lazy-init) singletons.beanFactory.preInstantiateSingletons();
}public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.// xml解析时,讲过,把所有beanName都缓存到beanDefinitionNames了List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {// 把父BeanDefinition里面的属性拿到子BeanDefinition中RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);//如果不是抽象的,单例的,非懒加载的就实例化if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//判断bean是否实现了FactoryBean接口,这里可以不看if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {//主要从这里进入,看看实例化过程getBean(beanName);}}}
}

其他详细内容,可以参考下这位大佬的文章:Spring的Bean实例化原理,这一次彻底搞懂了!

17、刷新上下文后置处理

afterRefresh 方法是启动后的一些处理,留给用户扩展使用,目前这个方法里面是空的。

/*** Called after the context has been refreshed.* @param context the application context* @param args the application arguments*/
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

18、结束计时器

到这一步,SpringBoot 其实就已经完成了,计时器会打印 SpringBoot 的启动时长。

在这里插入图片描述

在控制台看到启动还是挺快的,2秒多就启动完成了。

在这里插入图片描述

19、发布上下文准备就绪事件

告诉应用程序,我已经准备好了,可以开始工作了。

在这里插入图片描述

20、执行自定义的 run 方法

这是一个扩展功能,callRunners(context, applicationArguments) 可以在启动完成后执行自定义的 run 方法。有 2 种实现方式:

  1. 实现 ApplicationRunner 接口;
  2. 实现 CommandLineRunner 接口。

接下来我们验证一把,为了一次性验证全,我们把这2种方式都放在同一个类里面。

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;/*** 自定义启动后执行*/
@Component
public class MyRunner implements ApplicationRunner, CommandLineRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println(" 我是自定义的 run 方法1,实现 ApplicationRunner 接口即可运行");}@Overridepublic void run(String... args) throws Exception {System.out.println(" 我是自定义的 run 方法2,实现 CommandLineRunner 接口即可运行");}
}

启动 SpringBoot 后就可以看到控制台打印的信息了。

在这里插入图片描述

整理完毕,完结撒花~ 🌻





参考地址:

1.SpringBoot启动过程,https://blog.csdn.net/qq_42259971/article/details/127151316

2.Spring的Bean实例化原理,这一次彻底搞懂了!https://zhuanlan.zhihu.com/p/198087901

相关文章:

spring(15) SpringBoot启动过程

目录 一、过程简介二、过程流程图三、源码分析1、运行 SpringApplication.run() 方法2、确定应用程序类型3、加载所有的初始化器4、加载所有的监听器5、设置程序运行的主类6、开启计时器7、将 java.awt.headless 设置为 true8、获取并启用监听器9、设置应用程序参数10、准备环境…...

耕地单目标语义分割实践——Pytorch网络过程实现理解

一、卷积操作 &#xff08;一&#xff09;普通卷积&#xff08;Convolution&#xff09; &#xff08;二&#xff09;空洞卷积&#xff08;Atrous Convolution&#xff09; 根据空洞卷积的定义&#xff0c;显然可以意识到空洞卷积可以提取到同一输入的不同尺度下的特征图&…...

画质提升+带宽优化,小红书音视频团队端云结合超分落地实践

随着视频业务和短视频播放规模不断增长&#xff0c;小红书一直致力于研究&#xff1a;如何在保证提升用户体验质量的同时降低视频带宽成本&#xff1f; 在近日结束的音视频技术大会「LiveVideoStackCon 2023」上海站中&#xff0c;小红书音视频架构视频图像处理算法负责人剑寒向…...

【傅里叶级数与傅里叶变换】数学推导——3、[Part4:傅里叶级数的复数形式] + [Part5:从傅里叶级数推导傅里叶变换] + 总结

文章内容来自DR_CAN关于傅里叶变换的视频&#xff0c;本篇文章提供了一些基础知识点&#xff0c;比如三角函数常用的导数、三角函数换算公式等。 文章全部链接&#xff1a; 基础知识点 Part1&#xff1a;三角函数系的正交性 Part2&#xff1a;T2π的周期函数的傅里叶级数展开 P…...

第二章MyBatis入门程序

入门程序 创建maven程序 导入MyBatis依赖。pom.xml下导入如下依赖 <dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><dependen…...

AgentBench::AI智能体发展的潜在问题(二)

从历史上看&#xff0c;几乎每一种新技术的广泛应用都会在带来新机遇的同时引发很多新问题&#xff0c;AI智能体也不例外。从目前的发展看&#xff0c;AI智能体的发展可能带来的新问题可能包括如下方面&#xff1a; 第二是AI智能体的普及将有可能进一步加剧AI造成的技术性失业。…...

C++中的运算符总结(4):逻辑运算符(上)

C中的运算符总结&#xff08;4&#xff09;&#xff1a;逻辑运算符&#xff08;上&#xff09; 8、逻辑运算 NOT、 AND、 OR 和 XOR 逻辑 NOT 运算用运算符!表示&#xff0c;用于单个操作数。表 1是逻辑 NOT 运算的真值表&#xff0c;这种运算将提供的布尔标记反转&#xff1…...

Flink安装与使用

1.安装准备工作 下载flink Apache Flink: 下载 解压 [dodahost166 bigdata]$ tar -zxvf flink-1.12.0-bin-scala_2.11.tgz 2.Flinnk的standalone模式安装 2.1修改配置文件并启动 修改&#xff0c;好像使用默认的就可以了 [dodahost166 conf]$ more flink-conf.yaml 启动 …...

CentOS系统环境搭建(七)——Centos7安装MySQL

centos系统环境搭建专栏&#x1f517;点击跳转 坦诚地说&#xff0c;本文中百分之九十的内容都来自于该文章&#x1f517;Linux&#xff1a;CentOS7安装MySQL8&#xff08;详&#xff09;&#xff0c;十分佩服大佬文章结构合理&#xff0c;文笔清晰&#xff0c;我曾经在这篇文章…...

3.react useRef使用与常见问题

react useRef使用与常见问题 文章目录 react useRef使用与常见问题1. Dom操作: useRef()2. 函数组件的转发: React.forwardRef()3. 对普通值进行记忆, 类似于一个class的实例属性4. 结合useEffect,只在更新时触发FAQ 1. Dom操作: useRef() // 1. Dom操作: useRef()let app doc…...

Axios使用CancelToken取消重复请求

处理重复请求&#xff1a;没有响应完成的请求&#xff0c;再去请求一个相同的请求&#xff0c;会把之前的请求取消掉 新增一个cancelRequest.js文件 import axios from "axios" const cancelTokens {}export const addPending (config) > {const requestKey …...

九耶丨阁瑞钛伦特-Spring boot与Spring cloud 之间的关系

Spring Boot和Spring Cloud是两个相互关联的项目&#xff0c;它们可以一起使用来构建微服务架构。 Spring Boot是一个用于简化Spring应用程序开发的框架&#xff0c;它提供了自动配置、快速开发的特性&#xff0c;使得开发人员可以更加轻松地创建独立的、生产级别的Spring应用程…...

总结,由于顺丰的问题,产生了电脑近期一个月死机问题集锦

由于我搬家&#xff0c;我妈搞顺丰发回家&#xff0c;但是没有检查有没有坏&#xff0c;并且我自己由于不可抗力因素&#xff0c;超过了索赔时间&#xff0c;反馈给顺丰客服&#xff0c;说超过了造成了无法索赔的情况&#xff0c;现在总结发生了损坏配件有几件&#xff0c;显卡…...

C#程序配置读写例子 - 开源研究系列文章

今天讲讲关于C#的配置文件读写的例子。 对于应用程序的配置文件&#xff0c;以前都是用的ini文件进行读写的&#xff0c;这个与现在的json类似&#xff0c;都是键值对应的&#xff0c;这次介绍的是基于XML的序列化和反序列化的读写例子。对于ini文件&#xff0c;操作系统已经提…...

Angular中的管道Pipes

Angular中的管道&#xff08;Pipes&#xff09;是一种强大的工具&#xff0c;它可以处理和转换数据&#xff0c;然后将其呈现在视图中。它们可以被用于排序、格式化和过滤数据等任务。在本文中&#xff0c;我们将介绍Angular中的管道以及如何使用它们来简化开发过程。 管道的基…...

React入门 jsx学习笔记

一、JSX介绍 概念&#xff1a;JSX是 JavaScript XML&#xff08;HTML&#xff09;的缩写&#xff0c;表示在 JS 代码中书写 HTML 结构 作用&#xff1a;在React中创建HTML结构&#xff08;页面UI结构&#xff09; 优势&#xff1a; 采用类似于HTML的语法&#xff0c;降低学…...

sqlserver数据库中把一张表中的数据复制到另一张表中

我们在使用ERP时经常会遇到&#xff0c;把老系统的单据直接拉过来使用&#xff0c;但是对应的数据却没有&#xff0c;为空&#xff0c;这时候就需要把老系统数据库里的数据复制一份到新系统里&#xff0c;&#xff08;方法如下&#xff09; 1、如果是整个表复制表达如下&#…...

el-table 多个表格切换多选框显示bug

今天写了个功能&#xff0c;点击左侧的树做判断&#xff0c;一级树节点显示系统页面&#xff0c;二级树节点显示数据库页面&#xff0c;三级树节点显示表页面。 数据库页面和表页面分别有2个el-table ,上面的没有多选框&#xff0c;下面的有多选框 现在出现bug&#xff0c;在…...

UE5.2程序发布及运行问题记录

发布后的程序默认是以全屏模式启动运行的&#xff0c;通过添加以下命令行参数&#xff0c;可实现程序的窗口模式运行&#xff1a; -ResX1280 -ResY720 -WINDOWED 发布后的程序&#xff0c;启动时&#xff0c;提示显卡驱动警告&#xff08;如图1所示&#xff09;&#xff0c;但是…...

c语言strtol函数、strtod函数、strtoul函数浅悉

---------------- | strtol | ---------------- i.e. string to long long int strtol(const char *nptr, char **endptr, int base) strtol()会将nptr指向的字符串&#xff0c;根据参数base&#xff0c;按权转化为long int, 然后返回这个值。 参数base的范…...

Spark第三课

1.分区规则 1.分区规则 shuffle 1.打乱顺序 2.重新组合 1.分区的规则 默认与MapReduce的规则一致,都是按照哈希值取余进行分配. 一个分区可以多个组,一个组的数据必须一个分区 2. 分组的分区导致数据倾斜怎么解决? 扩容 让分区变多修改分区规则 3.HashMap扩容为什么必须…...

LangChain手记 Chains

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Chains&#xff08;源代码可见&#xff09; Chains 直译链&#xff0c;表达的意思更像是对话链&#xff0c;对话链的背后是思维链 LLM Chain&#xff08;LLM链&#xff09; 首先介绍了一个最简单的例子&#xff0c…...

ONNX版本YOLOV5-DeepSort (rknn版本已经Ready)

目录 1. 前言 2. 储备知识 3. 准备工作 4. 代码修改的地方 5.结果展示 1. 前言 之前一直在忙着写文档&#xff0c;之前一直做分类&#xff0c;检测和分割&#xff0c;现在看到跟踪算法&#xff0c;花了几天时间找代码调试&#xff0c;看了看&#xff0c;展示效果比单纯的检…...

MySQL的约束

文章目录 1、约束的概念2、约束的分类2.1 主键约束2.1.1 概念2.1.2 主键操作 2.2 自增约束2.2.1 概念2.2.2 自增操作 2.3 唯一约束2.3.1 概念2.3.2 唯一操作 2.4 非空约束2.4.1 概念2.4.2 非空操作 2.5 默认约束2.5.1 概念2.5.2 默认操作 2.6 外键约束2.6.1 概念2.6.2 外键操作…...

Lnton羚通关于【PyTorch】教程:torchvision 目标检测微调

torchvision 目标检测微调 本教程将使用Penn-Fudan Database for Pedestrian Detection and Segmentation 微调 预训练的Mask R-CNN 模型。 它包含 170 张图片&#xff0c;345 个行人实例。 定义数据集 用于训练目标检测、实例分割和人物关键点检测的参考脚本允许轻松支持添加…...

AMD fTPM RNG的BUG使得Linus Torvalds不满

导读因为在 Ryzen 系统上对内核造成了困扰&#xff0c;Linus Torvalds 最近在邮件列表中表达了对 AMD fTPM 硬件随机数生成器的不满&#xff0c;并提出了禁用该功能的建议。 因为在 Ryzen 系统上对内核造成了困扰&#xff0c;Linus Torvalds 最近在邮件列表中表达了对 AMD fTPM…...

idea 转换为 Maven Project 的方法

选项&#xff1a; Add as Maven Project...

es1.7.2 按照_type先聚合,再按照时间二次聚合

// 设置查询条件if (this.query ! null) {this.searchbuilder.setQuery(this.query);}TermsBuilder typeAggregation AggregationBuilders.terms("agg_type").field("_type");DateHistogramBuilder dateTermsBuilder AggregationBuilders.dateHistogram(…...

pyqt5 如何修改QplainTextEdit 背景色和主窗口的一样颜色

如果您希望将 QPlainTextEdit 的背景颜色设置为与窗口背景相似的灰色&#xff0c;您可以使用窗口的背景颜色作为基准来设置 QPlainTextEdit 的背景颜色。以下是一个示例代码&#xff0c;展示如何实现这一点&#xff1a; from PyQt5.QtWidgets import QApplication, QMainWindo…...

解决使用element ui时el-input的属性type=number,仍然可以输入e的问题。

使用element ui时el-input的属性typenumber&#xff0c;仍然可以输入e&#xff0c; 其他的中文特殊字符都不可以输入&#xff0c;但是只有e是可以输入的&#xff0c;原因是e也输入作为科学计数法的时候&#xff0c;e是可以被判定为数字的&#xff0c; 但是有些场景是需要把e这种…...

ShardingSphere 可观测 SQL 指标监控

ShardingSphere并不负责如何采集、存储以及展示应用性能监控的相关数据&#xff0c;而是将SQL解析与SQL执行这两块数据分片的最核心的相关信息发送至应用性能监控系统&#xff0c;并交由其处理。 换句话说&#xff0c;ShardingSphere仅负责产生具有价值的数据&#xff0c;并通过…...

Redisson实现分布式锁示例

一、引入依赖 <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.0</version></dependency>二、配置类 import org.redisson.Redisson; import org.redisson.api.RedissonClient;…...

使用Nginx作为一个普通代理服务器

使用Nginx作为一个普通代理服务器, 请不要用于违法用途哦 nginx作为一个反向代理工具&#xff0c;除了可以进行反向代理之外&#xff0c;还可以用来作为代理工具来使用&#xff0c;作为代理工具使用的步骤如下&#xff0c;这个配置目前支持80端口 Windows系统代理设置对应IP, …...

chatglm2-6b模型在9n-triton中部署并集成至langchain实践 | 京东云技术团队

一.前言 近期&#xff0c; ChatGLM-6B 的第二代版本ChatGLM2-6B已经正式发布&#xff0c;引入了如下新特性&#xff1a; ①. 基座模型升级&#xff0c;性能更强大&#xff0c;在中文C-Eval榜单中&#xff0c;以51.7分位列第6&#xff1b; ②. 支持8K-32k的上下文&#xff1b…...

Shell编程之正则表达式(非常详细)

正则表达式 1.通配符和正则表达式的区别2.基本正则表达式2.1 元字符 &#xff08;字符匹配)2.2 表示匹配次数2.4 位置锚定2.5 分组 和 或者 3.扩展正则表达式4.部分文本处理工具4.1 tr 命令4.2 cut命令4.3 sort命令4.4 uniq命令 1.通配符和正则表达式的区别 通配符一般用于文件…...

RNN模型简单理解和CNN区别

目录 神经网络&#xff1a;水平方向延伸&#xff0c;数据不具有关联性 ​ RNN&#xff1a;在神经网络的基础上加上了时间顺序&#xff0c;语义理解 ​RNN: 训练中采用梯度下降&#xff0c;反向传播 ​ 长短期记忆模型 ​输出关系&#xff1a;1 toN&#xff0c;N to N 单入…...

【Axure高保真原型】JS日期选择器筛选中继器表格

今天和大家分享JS日期选择器筛选中继器表格的原型模板&#xff0c;通过调用浏览器的日期选择器&#xff0c;所以可以获取真实的日历效果&#xff0c;具体包括哪一年二月份有29天&#xff0c;几号对应星期几&#xff0c;都是真实的&#xff0c;获取日期值后&#xff0c;通过交互…...

android bp脚本

一。android大约从7.0开始引入 .bp文件代替以前的.mk文件&#xff0c;用于帮助android项目的编译配置文件。 二。mk文件转化为bp文件&#xff0c;可以使用下面命令转化&#xff0c;注意命令中>&#xff0c;这是写入文件。androidmk是android源码自带的工具&#xff0c;他可…...

Redis 数据库 NoSQL

目录 一、NoSQL 二、为什么会出现NoSQL技术 三、NoSQL的类别 键值&#xff08;Key-Value&#xff09;存储数据库 列存储数据库 文档型数据库 图形&#xff08;Graph&#xff09;数据库 四、NoSQL适应场景 五、在分布式数据库中CAP原理 1、CAP 2、BASE 一、NoSQL NoS…...

RN 项目异常问题整理

常见问题 无法找到 CardStackStyleInterpolator StackViewStyleInterpolator 这个方法集来代替 CardStackStyleInterpolator的&#xff0c;这个方法集的路径也需要注意一下&#xff0c;在2.12.1版本之前&#xff0c; 该文件在react-navigation/src/views/StackView/中&#xf…...

STM8编程[TIM1多路PWM输出选项字节(Option Byte)操作和IO复用]

TIM1多路PWM输出选项字节(Option Byte)操作和IO复用 本文摘录于&#xff1a;https://blog.csdn.net/freeape/article/details/47008033只是做学习备份之用&#xff0c;绝无抄袭之意&#xff0c;有疑惑请联系本人&#xff01; 代码上要使用TIME1输出3路PWM,代码如下: void tim…...

Java算法_ 反转二叉树(LeetCode_Hot100)

题目描述&#xff1a;给你一棵二叉树的根节点 &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。root。 获得更多&#xff1f;算法思路:代码文档&#xff0c;算法解析的私得。 运行效果 完整代码 /*** 2 * Author: LJJ* 3 * Date: 2023/8/16 13:18* 4*/public class In…...

C/C++ 标准模版库STL(持续更新版)

标准模版库STL 目录 算法库 栈 队列 向量 映射 列表 双向链表 集合 Iterator 送代器 <algorithm> 算法库 max, min 用于找出一组值中的最大值和最小值 swap 用于交换两个变量的值 sort 用于对一个范围内的元素进行排序 lower_bound, upper_bound 用于在已排序的容器…...

ARM(实验二)

uart4.h #ifndef __H__ #define __H__#include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_uart.h"//RCC/GPIO/UART4章节初始化 void hal_uart4_init();//发送一个字符函数 void hal_put_char(const char str);//发…...

由“美”出发 听艺术家林曦关于美育与智慧的探讨

不久前&#xff0c;林曦老师与我们的老朋友「十点读书」进行了一次线上直播&#xff0c;有关林曦老师十余年的书法教学&#xff0c;和传统美育的心得&#xff0c;以及因此诞生的新书《无用之美》。      这一次的直播&#xff0c;由“美”的主题出发&#xff0c;延伸出美育…...

Serial与Parallel GC之间的不同之处是什么?

Serial GC(串行垃圾回收器)和Parallel GC(并行垃圾回收器)都是Java虚拟机(JVM)中用于进行垃圾回收的两种基本算法。它们在性能、资源利用和回收效率等方面存在一些不同之处。下面是它们之间的详细比较&#xff1a; 1.工作方式 Serial GC&#xff1a;它是一种单线程的垃圾回收器…...

GB28181设备接入侧如何对接外部编码后音视频数据并实现预览播放

技术背景 我们在对接GB28181设备接入模块的时候&#xff0c;遇到这样的技术诉求&#xff0c;好多开发者期望能提供编码后&#xff08;H.264/H.265、AAC/PCMA&#xff09;数据对接&#xff0c;确保外部采集设备&#xff0c;比如无人机类似回调过来的数据&#xff0c;直接通过模…...

【java】为什么文件上传要转成Base64?

文章目录 1 前言2 multipart/form-data上传3 Base64上传3.1 Base64编码原理3.2 Base64编码的作用 4 总结 1 前言 最近在开发中遇到文件上传采用Base64的方式上传&#xff0c;记得以前刚开始学http上传文件的时候&#xff0c;都是通过content-type为multipart/form-data方式直接…...

SCSS 学习笔记 和 vscode下载live sass compiler插件配置

1、下载livelive sass compiler插件并配置 // 在 已有代码 下面 添加下面 代码&#xff0c;一般刚刚下载打开最后一行是&#xff1a;// "liveSassCompile.settings.autoprefix": [],// 所以直接 把下面复制进去保存就行"liveSassCompile.settings.autoprefix&qu…...

CSS中的字体属性有哪些值,并分别描述它们的作用。

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ font-style⭐ font-weight⭐ font-size⭐ font-family⭐ font-variant⭐ line-height⭐ letter-spacing⭐ word-spacing⭐ font⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专…...