• springboot经典问题总结


    1.什么是springboot?

    springboot是spring开源组织下的一个子项目,是spring的一站式解决方案,主要是简化了spring的配置,提供了各种启动器,使开发者更容易上手。

    2.springboot的四大核心组件

    1、自动配置
    2、启动依赖
    3、Actuator
    4、命令行界面

    3.springboot的核心注解

    @SpringApplication是springboot的核心注解,它主要有以下几个注解组成:
    在这里插入图片描述

    1. @SpringbootConfiguration:组合了Configuration注解,实现配置文件功能。
    2. @EnableAutoConfiguration:打开自动配置功能,也可以关闭某个自动配置的选项
    3. ComponentScan:spring组件扫描

    4.Springboot的starter工作原理

    跟踪EnableAutoConfiguration注解,@EnableAutoConfiguration注解引入了 @Import 这个注解。
    在这里插入图片描述
    Import: 导入需要自动配置的组件,此处为AutoConfigurationImportSelector这个类
    找到这个类中的getCandidateConfigurations方法
    在这里插入图片描述
    AutoConfigurationImportSelector类的getCandidateConfigurations方法中的调用了SpringFactoriesLoader类的loadFactoryNames方法
    在这里插入图片描述
    在这里插入图片描述
    SpringFactoriesLoader中的静态方法loadFactoryNames从所有的jar中读取META-INF/spring.factories文件,自动配置的类就定义在这个文件中,这样spring boot就加载到这个自动配置类了。
    总结:
    1、Spring Boot启动时会去依赖的starter中寻找META-INF/spring.factories文件,然后根据文件中配置的jar包去扫描项目中所依赖的jar包
    在这里插入图片描述
    2、根据Spring Factories配置加载Auto Congifure类
    3、根据@Conditional注解的条件,进行自动配置并将bean注入spring
    在这里插入图片描述

    5.Async异步调用方法

    在springboot中异步调用方法,只需在方法上加@Async注解即可实现异步方法的调用了,注意,需要在启动类上加@EnableAsync注解

    6.springboot配置加载顺序

    1、properties文件
    2、YAML文件
    3、系统环境变量
    4、命令行参数等

    7.springboot配置多数据源

    1、在properties文件中配置多个数据源
    2、创建分包mapper,使用@ConfigurationProperties读取properties中的配置,使用@MapperScan注册到对应的mapper中
    在这里插入图片描述

    8.如何使用springboot的全局异常捕获器

    Spring 提供了一种使用 ControllerAdvice 处理异常的非常有用的方法。 我们通过实现一个
    ControlerAdvice 类,来处理控制器类抛出的所有异常。
    在这里插入图片描述

    9.springboot的监视器

    springboot能提供各个服务组件的度量,Spring Boot Actuator,它提供
    了一个 Web UI,使我们能够可视化多个应用程序的度量。

    10.springboot如何热部署

    引入devtools,只需重新编译即可实现热部署

    <dependency>
    	<groupId>org.springframework.bootgroupId>
    	<artifactId>spring-boot-devtoolsartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    11.springboot启动流程

    1、启动入口SpringApplication.run(JcStartServer.class,args);
    在这里插入图片描述
    第一步:new了一个SpringApplication对象
    第二步:调用了run方法
    在这里插入图片描述
    接下来看看new SpringApplication做了什么

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.sources = new LinkedHashSet();
            this.bannerMode = Mode.CONSOLE;
            this.logStartupInfo = true;
            this.addCommandLineProperties = true;
            this.addConversionService = true;
            this.headless = true;
            this.registerShutdownHook = true;
            this.additionalProfiles = new HashSet();
            this.isCustomEnvironment = false;
            this.lazyInitialization = false;
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            // 先把主类保存起来
            this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
            // 判断运行项目的类型
            this.webApplicationType = WebApplicationType.deduceFromClasspath();
            // 扫描当前路径下META-INF/spring.factories文件,加载ApplicationContextInitializer接口实例
            this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
            // 扫描当前路径下META-INF/spring.factories文件的,加载ApplicationListener接口实例
            this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = this.deduceMainApplicationClass();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    利用SPI机制扫描 META-INF/spring.factories 这个文件,并且加载 ApplicationContextInitializer、ApplicationListener 接口实例。

    1、ApplicationContextInitializer 这个类当springboot上下文Context初始化完成后会调用

    2、ApplicationListener 当springboot启动时事件change后都会触发
    下面我们来自定义ApplicationContextInitializer、ApplicationListener 接口实现类,然后Debug来看下效果。
    在这里插入图片描述
    在这里插入图片描述
    然后在META-INF/spring.factories 文件配置那两个类
    在这里插入图片描述

    在这里插入图片描述
    总结:上面就是SpringApplication初始化的代码,new SpringApplication()没做啥事情 ,利用SPI机制主要加载了META-INF/spring.factories 下面定义的事件监听器接口实现类
    2、执行run()方法

    public ConfigurableApplicationContext run(String... args) {
    		// 1、这是一个计时器
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            // 2、设置一些环境
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
            this.configureHeadlessProperty();
            // 3、获取事件监听器SpringApplicationRunListeners类型,并执行starting()方法
            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            listeners.starting();
    
            Collection exceptionReporters;
            try {
            	// 4、把参数args封装成DefaultApplicationArguments
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                // 5、准备环境,把环境跟spring上下文绑定好,并且执行environmentPrepared方法
                ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
                // 6、判断一些环境的值,并设置一些环境的值
                this.configureIgnoreBeanInfo(environment);
                // 7、打印branner
                Banner printedBanner = this.printBanner(environment);
                // 8、根据项目类型创建上下文
                context = this.createApplicationContext();
                // 9、获取异常报告事件监听
                exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
                // 10、准备上下文,执行完成后调用contextPrepared方法
                this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                // 11、这个是spring启动的代码,这里就要回去扫描并初始化单例bean了
                this.refreshContext(context);
                // 12、啥也没做
                this.afterRefresh(context, applicationArguments);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
                }
    
    			// 13、执行ApplicationListeners中的started()方法
                listeners.started(context);
                // 执行Runner
                this.callRunners(context, applicationArguments);
            } catch (Throwable var10) {
                this.handleRunFailure(context, var10, exceptionReporters, listeners);
                throw new IllegalStateException(var10);
            }
    
            try {
                listeners.running(context);
                return context;
            } catch (Throwable var9) {
                this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
                throw new IllegalStateException(var9);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    2.1、createApplicationContext()
    一起来看下context = createApplicationContext(); 这段代码,主要是根据项目类型创建上下文,并且注入几个核心组件类
    在这里插入图片描述
    注入一些spring的核心组件
    在这里插入图片描述
    Web类型项目创建上下文对象 AnnotationConfigServletWebServerApplicationContext 。这里会把 ConfigurationClassPostProcessor 、AutowiredAnnotationBeanPostProcessor 等一些核心组件加入到Spring容器
    2.2、refreshContext()
    下面一起来看下this.refreshContext(context);这段代码,这个方法启动spring的代码加载了bean,还启动了内置的tomcat
    在这里插入图片描述
    这边可以看到最后调用的是AbstractApplicationContext的refresh()方法,点进去发现是spring容器启动代码
    在这里插入图片描述
    spring启动源码之前写过了,这里就不看了,主要看onfresh()这个方法
    在这里插入图片描述
    因为我们启动的是web容器,所以就看ServletWebServerApplicationContext这子类
    ServletWebServerApplicationContext的关系图,它继承了AbstractApplicationContext
    在这里插入图片描述
    我们就去看ServletWebServerApplicationContext中的onfresh()方法,可以看createWebServer()方法,这就是启动内置web容器的入口。
    在这里插入图片描述
    this.getWebServerFactory()方法获取webServer工厂
    在这里插入图片描述
    这里会根据web容器类型获取bean
    在这里插入图片描述
    我们再回去看this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});代码
    在这里插入图片描述
    点进去就能看到一个很熟悉的名字tomcat
    总结:

    1、new了一个SpringApplication对象,使用SPI技术加载加载 ApplicationContextInitializer、ApplicationListener 接口实例

    2、调用SpringApplication.run() 方法

    3、调用createApplicationContext()方法创建上下文对象,创建上下文对象同时会注册spring的核心组件类(ConfigurationClassPostProcessor 、AutowiredAnnotationBeanPostProcessor 等)。

    4、调用refreshContext() 方法启动Spring容器和内置的Servlet容器

  • 相关阅读:
    【JAVA学习笔记】63 -坦克大战1.3-敌方发射子弹,击中坦克消失并爆炸,敌人坦克随机移动,规定范围限制移动
    前端代理模式之【策略模式】
    排序2:直接选择排序、堆排序、直接插入排序、希尔排序
    LeetCode 23. 合并 K 个升序链表
    关于生成式人工智能模型应用的调研
    合并集合(c++题解)
    【SQL】索引失效的11种情况
    Linux——指令初识(二)
    ARM 汇编编写 LED 灯
    【操作系统和进程】深入理解计算机内部运行的基本原理
  • 原文地址:https://blog.csdn.net/qq_45887180/article/details/126208715