spring(15) SpringBoot启动过程

news2024/12/28 3:31:52

目录

    • 一、过程简介
    • 二、过程流程图
    • 三、源码分析
      • 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 {
    @Override
    public 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;
    }

    @Override
    public 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 {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println(" 我是自定义的 run 方法1,实现 ApplicationRunner 接口即可运行");
    }

    @Override
    public 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

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

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

相关文章

【Golang系统开发】搜索引擎(2) 压缩词典

写在前面 这篇文章我们就给出一系列的数据结构&#xff0c;使得词典能达到越来越高的压缩比。当然&#xff0c;和倒排索引记录表的大小相比&#xff0c;词典只占据了非常小的空间。那么为什么要对词典进行压缩呢&#xff1f; 这是因为决定信息检索系统的查询响应时间的一个重…

《计算机网络:自顶向下方法》第五章--网络层:控制平面

控制平面作为一种网络范围的逻辑&#xff0c;不仅控制沿着从源主机到目的主机的端到端路径间的路由器如何转发数据报&#xff0c;而且控制网络层组件和服务如何配置和管理 传统上&#xff0c;控制平面功能与数据平面的转发功能在一起实现&#xff0c;在路由器中作为统一的整体…

IDEA 如何制作代码补丁?IDEA 生成 patch 和使用 patch

什么是升级补丁&#xff1f; 比如你本地修复的 bug&#xff0c;需要把增量文件发给客户&#xff0c;很多场景下大家都需要手工整理修改的文件&#xff0c;并整理好目录&#xff0c;这个很麻烦。那有没有简单的技巧呢&#xff1f;看看 IDEA 生成 patch 和使用 patch 的使用。 介…

Kafka—工作流程、如何保证消息可靠性

什么是kafka&#xff1f; 分布式事件流平台。希望不仅仅是存储数据&#xff0c;还能够数据存储、数据分析、数据集成等功能。消息队列&#xff08;把数据从一方发给另一方&#xff09;&#xff0c;消息生产好了但是消费方不一定准备好了&#xff08;读写不一致&#xff09;&am…

常量(constant)

1、概述 常量&#xff1a;是指在Java程序运行期间固定不变的数据。 2、分类 类型含义数据举例整数常量所有的整数0&#xff0c;1&#xff0c;567&#xff0c;-9 小数常量 &#xff08;浮点数常量&#xff09; 所有的小数0.0&#xff0c;-0.1&#xff0c;2.55字符常量单引号引起…

Python量化交易11——使用AKShare获取公司财务数据

AKshare库是一个很好用的金融数据获取的API&#xff0c;股票的数据很全面&#xff0c;还有很多别的数据&#xff1a; 链接&#xff1a;AKShare 股票数据 — AKShare 1.10.85 文档 他们获取来源都是东方财富网或者巨潮网等&#xff0c;都会写上的。 本次教大家怎么用AKshare获取…

第九章 动态规划part11(代码随想录)

123.买卖股票的最佳时机III 给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&#xff1a;你不能同时参与多笔交易&#xff08;你必须在再次购买前出售掉之前的股票&…

vscode如何汉化

首先我们到vscode官网下载 链接如下&#xff1a; Visual Studio Code - Code Editing. Redefined 根据自己需要的版本下载就好 下载并且安装完毕之后 运行vscode 然后按快捷键 CTRLSHIFTX 打开安装扩展界面 搜索简体中文 安装就可以了 谢谢大家观看

Matplotlib数据可视化(一)

目录 1.Matplotlib简介 2.Matplotlib绘图基础 2.1 创建画布与子图 2.2 添加画布属性 2.3 绘图的保存与显示 1.Matplotlib简介 Matplotlib是一个用于绘制数据可视化图表的Python库。它提供了广泛的功能和灵活性&#xff0c;可以创建各种类型的图表&#xff0c;包括折线图、…

Microsoft Edge浏览器开启ChatAI扩展

ChatAi每日可以免费使用5次&#xff0c;购买每月8.8&#xff0c;每年88。价格还不算贵 安装扩展过程&#xff1a; 打开 Microsoft Edge浏览器&#xff0c;点击右上角三个点&#xff0c;在扩展中选择加载项&#xff0c;在Microsoft Edge加载项中搜索openai&#xff0c;选择Chat…

kafka晋升之路-理论+场景

kafka晋升之路 一&#xff1a;故事背景二&#xff1a;核心概念2.1 系统架构2.2 生产者&#xff08;Producer&#xff09;2.2.1 生产者分区2.2.2 生产者分区策略 2.3 经纪人&#xff08;Broker&#xff09;2.3.1 主题&#xff08;Topic&#xff09;2.3.2 分区&#xff08;Partit…

人工智能与云计算实训室建设方案

一、 人工智能与云计算系统概述 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一种模拟人类智能的科学和工程&#xff0c;通过使用计算机系统来模拟、扩展和增强人类的智能能力。人工智能涉及多个领域&#xff0c;包括机器学习、深度学习、自然…

k8s简介及虚拟机快速搭建k8s集群

文章目录 1、k8s简介1.1、部署方式的变迁1.2、定义1.3、Kubernetes提供的功能 2、虚拟机快速搭建k8s集群2.1、虚拟机配置&#xff08;centos7 2G内存2个处理器&#xff09;2.2、基础环境准备2.3、docker安装&#xff08;易踩坑&#xff09;2.4、安装k8s组件2.5、master节点部署…

英飞凌在车辆信息安全方面上应用

如今&#xff0c;网络安全在多个层面影响着我们每个人。我们的专业工作、个人生活&#xff0c;甚至我们的汽车&#xff0c;都依赖于复杂软件上运行的连接和技术。随着信息技术日益融入我们的日常生活&#xff0c;我们对后续信息系统的依赖性也与日俱增。反过来&#xff0c;这些…

Win10+anaconda+CUDA+pytorch+vscode配置

Win10anacondaCUDApytorchvscode配置 1.安装anaconda2.安装CUDA确认CUDA版本确认CUDA和pytorch版本安装CUDA 3.安装cudnn4.安装Pytorch5.vscode配置安装VScodevscode配置pytorch环境 1.安装anaconda 官网https://www.anaconda.com 下载安装&#xff0c;路径全英文然后记得有一…

【微服务】springboot 整合mysql实现版本管理通用解决方案

目录 一、前言 1.1 单独执行初始化sql 1.2 程序自动执行 二、数据库版本升级管理问题 三、spring 框架sql自动管理机制 3.1 jdbcTemplate 方式 3.1.1 创建数据库 3.1.2 创建 springboot 工程 3.1.3 初始化sql脚本 3.1.4 核心配置类 3.1.5 执行sql初始化 3.2 配置文…

numpy基础知识

文章目录 安装numpynumpy的ndarray对象ndarray 和 list 效率比较创建一/二维数组ndarray的常用属性调整数组形状ndarray转list numpy的数据类型数组的运算数组和数的计算数组和数组的计算 数组的轴数组的索引和切片数组的与或非和三目运算符numpy的插入、删除、去重插入删除去重…

财务数据分析用什么软件好?财务数据分析的几个重要数据是什么?

财务的数据分析也分很多种的&#xff0c;就拿最粗略的划分来说&#xff0c;也可以分为3大领域—— 财务数据处理类工具财务数据挖掘类工具财务数据可视化工具 01 数据处理类 在财务数据处理这一块儿&#xff0c;不用说&#xff0c;当然是以excel为主力的数据处理类工具—— …

22年电赛B题——具有自动泊车功能的电动车——做题记录以及经验分享

前言 这道题目也是小车类电赛题目&#xff0c;十月份的电赛题&#xff0c;由于之前积累了一些经验&#xff0c;这道题目在做下来的感觉还行,但是我们看题目没有仔细审题&#xff0c;和题目要求有一些些偏差&#xff0c;但是基础大功能还是做出来辽&#xff0c;大家还是可以参考…

SASS 学习笔记 II

SASS 学习笔记 II 上篇笔记&#xff0c;SASS 学习笔记 中包含&#xff1a; 配置 变量 嵌套 这里加一个扩展&#xff0c;嵌套中有一个 & 的用法&#xff0c;使用 & 可以指代当前 block 中的 selector&#xff0c;后面可以追加其他的选择器。如当前的 scope 是 form&a…