【SpringBoot】基础
什么是 Spring Boot?
Spring Boot 是一个简化 Spring 应用程序开发的框架。它的主要目标是减少 Spring 应用程序的配置和开发复杂性,使我们能够更快地构建、测试和部署 Spring 应用。
简单来说它通过提供默认配置、自动化配置和嵌入式服务器等功能,简化了传统 Spring 应用的繁琐配置过程。
扩展知识
1)自动配置(Auto-Configuration):
Spring Boot 会根据项目中的依赖和配置自动配置 Spring 应用程序,无需手动编写大量的配置代码。可以通过 @EnableAutoConfiguration 注解和自动配置类(@Configuration)即可实现。
2)内嵌 web 服务器:
Spring Boot 支持嵌入式的 Web 服务器,如 Tomcat、Jetty 和 Undertow,使应用程序无需外部部署服务器,简化了开发和部署流程。
3)简化的依赖管理:
Spring Boot 提供了非常多的 starter 依赖,用于简化常见功能的依赖管理。例如 spring-boot-starter-web 包含了开发 Web 应用所需的常见依赖。
4)Spring Boot CLI:
Spring Boot CLI 是一个命令行工具,用于快速创建和运行 Spring Boot 应用程序。
5)Spring Boot Actuator:
提供了应用程序的监控和管理功能。包括健康检查、度量信息、环境信息等,方便对应用进行监控和管理。
6)Spring Boot DevTools:
是一个开发工具,提供热重启、LiveReload 和其他开发环境下的便利功能,可提升开发效率。
Spring Boot 的核心特性有哪些?
1)开箱即用,内嵌服务器。这个特点是程序员最直观的感受,相较于原本的开发,spring boot 可以省略以前繁琐的 tomcat 配置,快速创建一个 web 容器。
2)自动化配置。在 spring boot 中我们可以按照自动配置的规定(将自动加载的 bean 写在自己 jar 包当中的 meta/info/spring.factories 文件中或者通过的注解 @Import 导入时加载指定的类)这样我们的配置类就会被 springboot 自动加载到容器当中。 同时还支持通过改写yaml 和 propreties来覆盖默认配置
3)支持 jar 包运行。传统部署web 容器都是打成 war 包放在 tomcat 中。spring boot 可以打成 jar 包只要有 java 运行环境即可运行 web 容器。
4)完整的生态支持。springboot 可以随意整合 spring 全家桶的支持。像 Actuator 健康检查模块,Spring Data JPA 数据库模块,Spring Test 测试模块。这些都可以很优雅的集成在 springboot 当中
扩展知识
面试时可以跟面试官说说自己是如何实现一个 spring boot starter 来帮助项目简化某些通用的业务的。
比如现在项目中有很多列表接口需要导出 excel。我利用自动化配置写了一个 excel 导出模块。
实现思路如下:
1)写一个 @ExcelExport 注解,放在列表接口上。利用切面来切列表的返回结果,拿到列表结果后写入 excel 当中。
2)然后写一个配置类放在 meta/info/spring.factories 文件下。这样让 spring boot 自动装配我们这个写 excel 文件的处理类。
3)在整个项目中有需要列表导出 excel 的地方,仅需把注解写在列表接口上即可。
通过这个例子让面试官相信你有实际使用自动化装配的经验。
Spring Boot 是如何通过 main 方法启动 web 项目的?
Spring Boot 应用的启动流程都封装在 SpringApplication.run 方法中,它的大部分逻辑都是复用 Spring 启动的流程,只不过在它的基础上做了大量的扩展。
在启动的过程中有一个刷新上下文的动作,这个方法内会触发 webServer 的创建,此时就会创建并启动内嵌的 web 服务,默认的 web 服务就是 tomcat。
分析
SpringApplication.run 方法实际上会触发 refreshContext 方法
最终会调用到 ServletWebServerApplicationContext.onRefresh 方法,这个方法内会调用 createWebServer
createWebServer 从名字就能理解这个方法是干嘛的,可以看到内部通过一个 ServletWebServerFactory 获取 webServer
默认的 WebServer 是 tomcat,可以看到源码里就是直接 new 了一个 Tomcat,且包装成一个 WebServer:
实际上这个 getTomcatWebServer 会 new 一个 WebServer:
而 new WebServer 会触发 initialize 方法,这个方法内就会触发 tomcat.start:
这个时候 tomcat 就被启动了,web 服务就起来了!
这里再扩展下,实际上有 5 种 webServer,默认用的是 TomcatWebServer,还有 jetty、undertow 等。
Spring Boot 中 application.properties 和 application.yml 的区别是什么?
它们两者的区别就在于书写格式,对配置而言效果是一样的,就是个人偏好问题。
application.properties 使用键值对配置,键和值之间用等号或冒号分隔
application.yml 使用 YAML (YAML Ain’t Markup Language)格式,具有层级结构,使用缩进表示嵌套关系。适合复杂配置,阅读性更佳。
如何在 Spring Boot 中定义和读取自定义配置?
简单来看可以有三种:
1)使用 @Value 注解:
|
2)使用 @ConfigurationProperties 注解:
|
3)使用 Environment 接口:
|
Spring Boot 配置文件加载优先级你知道吗?
简单优先级:
命令行参数 > JAR包外面的 application-{profile}.properties
> JAR包内的 application-{profile}.properties
> JAR包外的 application.properties
> JAR包内的 application.properties
注意:
当 application.properties
和 application.yml
同时存在,同样的参数,最终生效的是 application.properties
中的配置。
扩展 bootstrap 和 application 配置文件知识:
boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载,且它里面的内容不会被覆盖!
比如一些配置中心的配置,需要填写在 boostrap 中,父上下文先去配置中心获取额外的一些配置,然后再启动 SpringBoot 上下文。
SpringBoot 的启动流程?
启动类
|
@SpringBootApplication
这些注解虽然看起来很多,但是除去元注解,真正起作用的注解只有以下三个注解:
@SpringBootConfiguration
@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类, 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。
@ComponentScan
@ComponentScan 的作用就是扫描当前包以及子包,将有@Component,@Controller,@Service,@Repository等注解的类注册到容器中,以便调用。
注:如果@ComponentScan不指定basePackages,那么默认扫描当前包以及其子包,而@SpringBootApplication里的@ComponentScan就是默认扫描,所以我们一般都是把springboot启动类放在最外层,以便扫描所有的类。
@EnableAutoConfiguration
这里先总结下@EnableAutoConfiguration
的工作原理,大家后面看的应该会更清晰: 它主要就是通过内部的方法,扫描classpath的META-INF/spring.factories配置文件(key-value),将其中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项实例化并且注册到spring容器。
ok,我们同样打开@EnableAutoConfiguration源码,可以发现他是由以下几个注解组成的:
除去元注解,主要注解就是@AutoConfigurationPackage
和@Import(AutoConfigurationImportSelector.class)
。我们springboot项目为什么可以自动载入应用程序所需的bean?就是因为这个神奇的注解@Import。那么这个@Import怎么这么牛皮?没关系!我们一步一步的看下去!
首先我们先进入AutoConfigurationImportSelector类,可以看到他有一个方法selectImports()
继续跟踪,进入getAutoConfigurationEntry()方法,可以看到这里有个List集合,那这个List集合又是干嘛的?没事,我们继续跟踪getCandidateConfigurations()方法!
可以看到这里有个方法,这个方法的作用就是读取classpath下的META-INF/spring.factories文件的配置,将key为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项读取出来,通过反射机制实例化为配置文件,然后注入spring容器。
注:假如你想要实例化一堆bean,可以通过配置文件先将这些bean实例化到容器,等其他项目调用时,在spring.factories中写入这个配置文件的路径即可!
小结
SpringApplication.run()
SpringApplication创建
|
获取应用类型
跟踪deduceFromClasspath方法:
从返回结果我们可以看出应用类型一共有三种,分别是
- NONE: 非web应用,即不会启动服务器
- SERVLET: 基于servlet的web应用
- REACTIVE: 响应式web应用(暂未接触过)
判断一共涉及四个常量:
- WEBFLUX_INDICATOR_CLASS
- WEBMVC_INDICATOR_CLASS
- JERSEY_INDICATOR_CLASS
- SERVLET_INDICATOR_CLASSES
springboot在初始化容器的时候,会对以上四个常量所对应的class进行判断,看看他们是否存在,从而返回应用类型!
获取初始化器
跟踪进入getSpringFactoriesInstances方法:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { |
从代码可以看出是在META-INF/spring.factories配置文件里获取初始化器,然后实例化、排序后再设置到initializers属性中
获取初监听器
监听器和初始化的操作是基本一样的
定位main方法
跟踪源码进入deduceMainApplicationClass方法:
private Class<?> deduceMainApplicationClass() { |
创建小结
创建了SpringApplication实例之后,就完成了SpringApplication类的初始化工作,这个实例里包括监听器、初始化器,项目应用类型,启动类集合,类加载器。如图所示。
run()方法
public ConfigurableApplicationContext run(String... args) { |
如何在 SpringBoot 启动时执行特定代码?有哪些方式?
常见一共有六种方式:
1、实现 CommandLineRunner 接口
CommandLineRunner 接口用于在 Spring Boot 应用启动完成后,执行特定的代码逻辑。可以有多个实现类,按照 @Order 注解的顺序执行。
|
2、实现 ApplicationRunner 接口
ApplicationRunner 接口与 CommandLineRunner 类似,但可以接受和处理 ApplicationArguments 对象。
ApplicationArguments 其实就是获取应用程序启动参数。
例如 idea 可以在这里配置启动参数:
|
3、使用 @PostConstruct 注解
Spring 容器初始化 bean 后,会执行初始化方法。这个注解适用于需要在 bean 初始化后立即执行的代码。
|
4、使用 InitializingBean 接口
InitializingBean 接口提供了 afterPropertiesSet 方法,用于在 Spring 容器初始化 bean 的属性后,执行特定的初始化逻辑。
|
5、使用 Spring 事件监听器
可以通过监听 Spring 的 ContextRefreshedEvent 期事件,在应用启动时执行特定代码。
|
6、自定义 BeanFactoryPostProcessor 和 BeanPostProcessor
它们都是 Spring 容器启动给的扩展点,可以在 Spring 容器初始化 bean 之前或之后执行特定逻辑。
|
Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?
Spring Boot 打成的 JAR 包不仅包含了应用程序的源代码和依赖库,还包含了程序运行需要的配置、脚本和服务依赖(内嵌的服务器如 Tomcat、Jetty、Undertow),可以直接部署运行。
普通的 JAR 包只有源代码和一些依赖,通常需要外部服务器或容器来运行。
参考链接
SpringBoot启动都做了什么?看完就懂了! - 知乎 (zhihu.com)
Spring Boot:最全SpringBoot启动流程原理分析(全网最全最完善)-腾讯云开发者社区-腾讯云 (tencent.com)