springboot经典问题总结

导读:本篇文章讲解 springboot经典问题总结,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

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.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
</dependency>

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

利用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);
        }
    }

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容器

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/90983.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!