SpringBoot面试总结一

1、什么是springboot

答案1:

用来简化spring应用的初始搭建以及开发过程使用特定的方式来进行配置(properties或yml文件)、
创建独立的spring引用程序main方法运行、
嵌入的Tomcat 无需部署war文件、
简化maven配置、
自动配置spring添加对应功能starter自动化配置
答:spring boot来简化spring应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用

答案2:

Spring Boot是Spring开源组织下的子项目,是Spring组件一站式解决方案,主要是简化了使用Spring的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。

答案3:

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。用我的话来理解,就是spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架(不知道这样比喻是否合适)。

2、Spring Boot的优点(为什么要用 Spring Boot?)

答案1:

使用spring boot有什么好处,其实就是简单、快速、方便!
平时如果我们需要搭建一个springweb项目的时候需要怎么做呢:
1)配置web.xml,加载spring和springmvc
2)配置数据库连接、配置spring事务
3)配置加载配置文件的读取,开启注解
4)配置日志文件

配置完成之后部署tomcat 调试

现在非常流行微服务,如果我这个项目仅仅只是需要发送一个邮件,如果我的项目仅仅是生产一个积分;我都需要这样折腾一遍!

答案2:

1 快速创建独立运行的spring项目与主流框架集成
2 使用嵌入式的servlet容器,应用无需打包成war包
3 starters自动依赖与版本控制
4 大量的自动配置,简化开发,也可修改默认值
5 准生产环境的运行应用监控
6 与云计算的天然集成

答案3:

独立运行、简化配置、自动配置、无代码生成和XML配置、应用监控、快速上手。。。

1独立运行

Spring Boot而且内嵌了各种servlet容器,Tomcat、Jetty等,现在不再需要打成war包部署到容器中,Spring Boot只要打成一个可执行的jar包就能独立运行,所有的依赖包都在一个jar包内。

2 简化配置

spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置。
+-org.springframework.boot:spring-boot-starter-web:jar:1.5.6.RELEASE:compile
+-org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.6.RELEASE:compile
| +-org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.16:compile
| +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.16:compile
| -org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.16:compile
+- org.hibernate:hibernate-validator:jar:5.3.5.Final:compile
| +- javax.validation:validation-api:jar:1.1.0.Final:compile
| +- org.jboss.logging:jboss-logging:jar:3.3.1.Final:compile
| - com.fasterxml:classmate:jar:1.3.3:compile
- org.springframework:spring-webmvc:jar:4.3.10.RELEASE:compile

3 自动配置

Spring Boot能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starter-web启动器就能拥有web的功能,无需其他配置。

4 无代码生成和XML配置

Spring Boot配置过程中无代码生成,也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的,这也是Spring4.x的核心功能之一。

5 应用监控

Spring Boot提供一系列端点可以监控服务及应用,做健康检测。

6 快速上手

。。。。

3、Spring Boot的缺点

Spring Boot虽然上手很容易,但如果你不了解其核心技术及流程,所以一旦遇到问题就很棘手,而且现在的解决方案也不是很多,需要一个完善的过程。

4、springboot读取配置文件的方式

springboot默认读取配置文件为application.properties或者是application.yml

5、Spring Boot 的核心配置文件有哪几个?它们的区别是什么?

Spring Boot 的核心配置文件

application (.yml 或者 .properties)
bootstrap (.yml 或者 .properties)

bootstrap/ application 的区别

Spring Cloud 构建于 Spring Boot 之上,在 Spring Boot 中有两种上下文,一种是 bootstrap, 另外一种是 application, bootstrap 是应用程序的父上下文,也就是说bootstrap 加载优先于 applicaton。bootstrap 主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,它是任何Spring应用程序的外部属性的来源。bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。
因此,对比application 配置文件,bootstrap 配置文件具有以下几个特性:
1 boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载
2 boostrap 里面的属性不能被覆盖

bootstrap/ application 的应用场景

application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有以下几个应用场景:
1 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
2 一些固定的不能被覆盖的属性;
3 一些加密/解密的场景;

6、Spring Boot 的配置文件有哪几种格式?它们有什么区别?

.properties和 .yml,它们的区别主要是书写格式不同。
1).properties
app.user.name = javastack
2).yml
app:
user:
name: javastack
另外,.yml 格式不支持 @PropertySource 注解导入配置。

7、Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解。
主要组合包含了以下 3个注解:
1 @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
2 @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,
如关闭数据源自动配置功能:
@SpringBootApplication(exclude= { DataSourceAutoConfiguration.class })。
3 @ComponentScan:Spring组件扫描。

8、开启 Spring Boot 特性有哪几种方式?

1)继承spring-boot-starter-parent项目
2)导入spring-boot-dependencies项目依赖

具体请参考这篇文章《Spring Boot开启的2种方式》。

9、如何重新加载Spring Boot上的更改,而无需重新启动服务器?

这可以使用DEV工具来实现。通过这种依赖关系,您可以节省任何更改,嵌入式tomcat将重新启动。
Spring Boot有一个开发工具(DevTools)模块,它有助于提高开发人员的生产力。Java开发人员面临的一个主要挑战是将文件更改自动部署到服务器并自动重启服务器。
开发人员可以重新加载Spring Boot上的更改,而无需重新启动服务器。这将消除每次手动部署更改的需要。Spring Boot在发布它的第一个版本时没有这个功能。
这是开发人员最需要的功能。DevTools模块完全满足开发人员的需求。该模块将在生产环境中被禁用。它还提供H2数据库控制台以更好地测试应用程序。
org.springframework.boot
spring-boot-devtools
true

10、Spring Boot中的监视器是什么?

Spring boot actuator是spring启动框架中的重要功能之一。Spring boot监视器可帮助您访问生产环境中正在运行的应用程序的当前状态。
有几个指标必须在生产环境中进行检查和监控。即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息。监视器模块公开了一组可直接作为HTTP URL访问的REST端点来检查状态。

11、什么是YAML?

YAML是一种人类可读的数据序列化语言。它通常用于配置文件。
与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML文件就更加结构化,而且更少混淆。可以看出YAML具有分层配置数据。

12、springboot常用的starter有哪些

spring-boot-starter-web 嵌入tomcat和web开发需要servlet与jsp支持
spring-boot-starter-data-jpa 数据库支持
spring-boot-starter-data-redis redis 数据库支持
spring-boot-starter-data-solr solr支持
mybatis-spring-boot-starter 第三方的mybatis集成starter

13、springboot自动配置的原理

在spring程序main方法中添加@SpringBootApplication或者@EnableAutoConfiguration会自动去maven中读取每个starter中的spring.factories文件。该文件里配置了所有需要被创建spring容器中的bean。

14、springboot集成mybatis的过程

添加mybatis的startermaven依赖
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.2.0
在mybatis的接口中 添加@Mapper注解
在application.yml配置数据源信息

15、Spring Boot 需要独立的容器运行吗?

可以不需要,内置了 Tomcat/ Jetty 等容器。

16、运行 Spring Boot 有哪几种方式?

1)打包用命令或者放到容器中运行
2)用 Maven/ Gradle 插件运行
3)直接执行 main 方法运行

17、Spring Boot 自动配置原理是什么?

注解 @EnableAutoConfiguration,@Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。

具体看这篇文章《Spring Boot自动配置原理、实战》。

18、Spring Boot 的目录结构是怎样的?

cn
+-javastack
+-MyApplication.java
|
+-customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+-order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java
这个目录结构是主流及推荐的做法,而在主入口类上加上@SpringBootApplication 注解来开启 Spring Boot 的各项能力,如自动配置、组件扫描等。具体看这篇文章《Spring Boot 主类及目录结构介绍》。

19、你如何理解 Spring Boot 中的 Starters?

Starters是什么?

Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 SpringJPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。
Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。

Starters命名

Spring Boot官方的启动器都是以spring-boot-starter-命名的,代表了一个特定的应用类型。
第三方的启动器不能以spring-boot开头命名,它们都被Spring Boot官方保留。一般一个第三方的应该这样命名,像mybatis的mybatis-spring-boot-starter。

Starters分类

1. Spring Boot应用类启动器

SpringBoot面试必备知识点 - 图1

2. Spring Boot生产启动器

SpringBoot面试必备知识点 - 图2

3. Spring Boot技术类启动器

SpringBoot面试必备知识点 - 图3

4. 其他第三方启动器

更多可以参考下面链接。
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-starters/README.adoc

20、如何在 Spring Boot 启动的时候运行一些特定的代码?

Runner启动器

如果你想在Spring Boot启动的时候运行一些特定的代码,你可以实现接口 ApplicationRunner或者 CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法。
CommandLineRunner:启动获取命令行参数。

  1. public interface CommandLineRunner {
  2. /**
  3. * Callback used to run the bean.
  4. * @param args incoming main method arguments
  5. * @throws Exception on error
  6. */
  7. void run(String... args) throws Exception;
  8. }

ApplicationRunner:启动获取应用启动的时候参数。

  1. public interface ApplicationRunner {
  2. /**
  3. * Callback used to run the bean.
  4. * @param args incoming application arguments
  5. * @throws Exception on error
  6. */
  7. void run(ApplicationArguments args) throws Exception;
  8. }

使用方式

  1. import org.springframework.boot.*
  2. import org.springframework.stereotype.*
  3. @Component
  4. public class MyBean implements CommandLineRunner {
  5. public voidrun(String... args) {
  6. //Do something...
  7. }
  8. }

或者这样

  1. @Bean
  2. public CommandLineRunner init() {
  3. return(String... strings) -> {
  4. };
  5. }

启动顺序

如果启动的时候有多个ApplicationRunner和CommandLineRunner,想控制它们的启动顺序,可以
实现org.springframework.core.Ordered接口,或者
使用 org.springframework.core.annotation.Order注解。

21、Spring Boot 有哪几种读取配置的方式?

读取application文件

在application.yml或者properties文件中添加:
info.address=USA
info.company=Spring
info.degree=high

@Value注解读取方式

  1. importorg.springframework.beans.factory.annotation.Value;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class InfoConfig1 {
  5. @Value("${info.address}")
  6. private String address;
  7. @Value("${info.company}")
  8. private String company;
  9. @Value("${info.degree}")
  10. private String degree;
  11. public String getAddress() {
  12. return address;
  13. }
  14. public void setAddress(String address) {
  15. this.address = address;
  16. }
  17. public String getCompany() {
  18. return company;
  19. }
  20. public void setCompany(String company) {
  21. this.company = company;
  22. }
  23. public String getDegree() {
  24. return degree;
  25. }
  26. public void setDegree(String degree) {
  27. this.degree = degree;
  28. }
  29. }

@ConfigurationProperties注解读取方式

  1. @Component
  2. @ConfigurationProperties(prefix = "info")
  3. public class InfoConfig2 {
  4. private String address;
  5. private String company;
  6. private String degree;
  7. public String getAddress() {
  8. return address;
  9. }
  10. public void setAddress(String address) {
  11. this.address = address;
  12. }
  13. public String getCompany() {
  14. return company;
  15. }
  16. public void setCompany(String company) {
  17. this.company = company;
  18. }
  19. public String getDegree() {
  20. return degree;
  21. }
  22. public void setDegree(String degree) {
  23. this.degree = degree;
  24. }
  25. }

读取指定文件

资源目录下建立config/db-config.properties:
db.username=root
db.password=123456

@PropertySource+@Value注解读取方式

  1. @Component
  2. @PropertySource(value = { "config/db-config.properties" })
  3. public class DBConfig1 {
  4. @Value("${db.username}")
  5. private String username;
  6. @Value("${db.password}")
  7. private String password;
  8. public String getUsername() {
  9. return username;
  10. }
  11. public void setUsername(String username) {
  12. this.username = username;
  13. }
  14. public String getPassword() {
  15. return password;
  16. }
  17. public void setPassword(String password) {
  18. this.password = password;
  19. }
  20. }

注意:@PropertySource不支持yml文件读取。

@PropertySource+@ConfigurationProperties注解读取方式

  1. @Component
  2. @ConfigurationProperties(prefix = "db")
  3. @PropertySource(value = { "config/db-config.properties" })
  4. public class DBConfig2 {
  5. private String username;
  6. private String password;
  7. public String getUsername() {
  8. return username;
  9. }
  10. public void setUsername(String username) {
  11. this.username = username;
  12. }
  13. public String getPassword() {
  14. return password;
  15. }
  16. public void setPassword(String password) {
  17. this.password = password;
  18. }
  19. }

Environment读取方式

以上所有加载出来的配置都可以通过Environment注入获取到。

  1. @Autowired
  2. private Environment env;
  3. // 获取参数
  4. String getProperty(String key);

总结

Spring Boot 可以通过 ,
@PropertySource,@Value,@Environment,@ConfigurationProperties 来绑定变量。

22、Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?

Spring Boot 支持 Java Util Logging, Log4j2, Lockback 作为日志框架,如果你使用 Starters 启动器,Spring Boot 将使用 Logback 作为默认日志框架,具体请看这篇文章《Spring Boot日志集成》。

23、SpringBoot 实现热部署有哪几种方式?

主要有两种方式:
1 Spring Loaded
2 Spring-boot-devtools
Spring-boot-devtools使用方式可以参考这篇文章《Spring Boot实现热部署》。

24、你如何理解 Spring Boot 配置加载顺序?

在 SpringBoot 里面,可以使用以下几种方式来加载配置。
1)properties文件;
2)YAML文件;
3)系统环境变量;
4)命令行参数;
等等……
具体请看这篇文章《SpringBoot 配置加载顺序详解》。

25、Spring Boot 如何定义多套不同环境配置?

提供多套配置文件,如:
applcation.properties
application-dev.properties
application-test.properties
application-prod.properties
运行时指定具体的配置文件,具体请看这篇文章《Spring Boot Profile 不同环境配置》。

26、Spring Boot 可以兼容老 Spring 项目吗,如何做?

可以兼容,使用 @ImportResource 注解导入老 Spring 项目配置文件。

27、如何集成Spring Boot和ActiveMQ?

对于集成Spring Boot和ActiveMQ,我们使用spring-boot-starter-activemq依赖关系。它只需要很少的配置,并且不需要样板代码。

28、保护 Spring Boot 应用有哪些方法?

在生产中使用HTTPS
使用Snyk检查你的依赖关系
升级到最新版本
启用CSRF保护
使用内容安全策略防止XSS攻击

更多请看这篇文章《10 种保护Spring Boot 应用的绝佳方法》。

29、Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?

配置变更
JDK 版本升级
第三方类库升级
响应式 Spring 编程支持
HTTP/2 支持
配置属性绑定
更多改进与加强…
具体请看这篇文章《Spring Boot 2.x 新特性总结及迁移指南》。

SpringBoot面试总结二

1、Spring Boot是什么

SpringBoot面试必备知识点 - 图4
SpringBoot是伴随着Spring4.0诞生的;
从字面理解,Boot是引导的意思,因此SpringBoot帮助开发者快速搭建Spring框架;
SpringBoot帮助开发者快速启动一个Web容器;
SpringBoot继承了原有Spring框架的优秀基因;
SpringBoot简化了使用Spring的过程。

2、Spring Boot解决了哪些问题

1) Spring Boot使编码变简单

SpringBoot面试必备知识点 - 图5

2) Spring Boot使配置变简单

Spring由于其繁琐的配置,一度被人认为“配置地狱”,各种XML、Annotation配置,让人眼花缭乱,而且如果出错了也很难找出原因。
Spring Boot更多的是采用Java Config的方式,对Spring进行配置。
SpringBoot面试必备知识点 - 图6

3) Spring Boot使部署变简单

SpringBoot面试必备知识点 - 图7

4) Spring Boot使监控变简单


SpringBoot面试必备知识点 - 图8

3、Spring Boot的不足

可以看到,采用了spring-boot-start-actuator之后,直接以REST的方式,获取进程的运行期性能参数。
当然这些metrics有些是有敏感数据的,spring-boot-start-actuator为此提供了一些BasicAuthentication认证的方案,这些方案在实际应用过程中也是不足的。
SpringBoot面试必备知识点 - 图9

4、Spring Boot在平台中的定位,相关技术如何融合

Spring Boot作为一个微框架,离微服务的实现还是有距离的。
没有提供相应的服务发现和注册的配套功能,自身的acturator所提供的监控功能,也需要与现有的监控对接。没有配套的安全管控方案,对于REST的落地,还需要自行结合实际进行URI的规范化工作。

SpringBoot相关技术

SpringBoot面试必备知识点 - 图10

SpringBoot与SEDA +MicroService +RESTful

SpringBoot面试必备知识点 - 图11

上图比较复杂,整体是采用SEDA,也就是Stage-EDA。可以看到,整体是以处理顺序进行展示的,响应过程类似。在处理过程中,主要会有前置过滤,核心功能处理,后置过滤几大部分。
图中的过滤器都是可插拔式的,并且可以根据实际场景进行扩展开发。每个过滤器都是Stage,比如ClientInstance合法性检查、调用鉴权、解密、限流等等。
一个请求Stage与Stage的转换,实现上是切换不同的线程池,并以EDA的方式驱动。
对于业务逻辑的开发者而言,只需要关心CORE部分的业务逻辑实现,其他的非功能都由框架进行统一实现。

SpringBoot与Mock

SpringBoot面试必备知识点 - 图12

Mock不应当再是测试的专有名词了,当然对于测试这个角色而言,mockito这样的工具,依然可以为他们提升不少效率。
SpringBoot为创建REST服务提供了简便的途径,相比之下,采用阿里的dubbo在做多团队、多进程联调时,mock的难度就陡增。
Mock是解耦并行开发的利器,在理性的情况下,软件从开发期Mock联调,到开发与开发的真实联调,只需要切换一个依赖的域名即可,比如:
mockURI:http://mock.service.net/v1/function?param1=value1
devURI:http://dev.service.net/v1/function?param1=value1
而上述的域名切换,只需要在开发期定义好一个配置项,在做环境切换的时候自动注入即可,省时、省心、省力。

SpringBoot与Docker

SpringBoot面试必备知识点 - 图13

如上图和docker的集成可以有AB两种方案:
• A方案的核心是,把docker作为操作系统环境的交付基线,也就是不同的fat jar 使用相同的操作系统版本、相同的JVM环境。但对于docker image来说都是一样的。
• B方案的核心是,不同的fat jar,独立的编译为docker image,在启动时直接启动带有特定版本的image。
A相比与B方案的特点是对于dockerregistry(也就是docker的镜像仓库)的依赖性较低,对于前期编译过程的要求也较低。
采用了SpringBoot之后,技术管理应该如何进行?
SpringBoot面试必备知识点 - 图14
正因为SpringBoot是与Spring一脉相承的,所以对于广大的Java开发者而言,对于Spring的学习成本几乎为零。
在实践SpringBoot时学习重点,或者说思维方式改变的重点在于:
1)对于REST的理解,这一点尤为重要,需要从设计、开发多个角色达成共识,很多时候都是对于HTTP 1.1协议以及REST的精髓不理解,导致REST被「盲用」而产生一些不好的效果。
2)对于YAML的理解和对于JavaConfig的理解,这两点相对较为简单,本质上是简化了xml文件,并提供等价的配置表述能力。
SpringBoot面试必备知识点 - 图15
1. 丰富的工具链为SpringBoot的推广带来了利好。
2. SpringBoot的工具链主要来自于两个方面:
1)原有Spring积累的工具链;
2)SpringMVC或者其他REST框架使用HTTP协议,使得HTTP丰富的工具成为SpringBoot天然的资源。
SpringBoot面试必备知识点 - 图16
SpringBoot自身对于前面提到的配置文件:“application.yml”提供了多个「Profile」,可以便于开发者描述不同环境的配置,这些配置例如数据库的连接地址、用户名和密码。
但是对于企业用户而言,把不同环境的配置,写到同一个配置文件中,是极其不安全的,是一个非常危险的动作。
有一个经常被提及的例子是,随着开源的进行,很多互联网公司,都由于把相关的代码提交到github之类的开源代码社区,并且没有对代码进行严格的配置审查,导致一些”password”被公开。有些不良用心的人,就利用搜索工具,专门去挖掘这些关键字,进而导致数据库被「拖库」。
所以对于企业用户,更多的应该是采用集中式的配置管理系统,将不同环境的配置严格区分地存放。
虽然SpringBoot的actuator自身提供了基于「用户名+口令」的最简单的认证方式,但它保护的是对框架自身运行期的性能指标敏感数据的最基本的保护。这种保护在实际应用过程中,「用户名+口令」的管理是缺乏的,「用户名+口令」的安全配置过程是缺失的。
SpringBoot也不提供对于我们自己开发的功能的任何防护功能。
一般来讲,一个安全的信道(信息传输的通道),需要通信双方在进行正式的信息传输之前对对方进行身份认证,服务提供方还需要在此基础之上,对请求方的请求进行权限的校验,以确保业务安全。这些内容也需要基于SpringBoot进行外围的安全扩展,例如采用前面提到的S-EDA进行进程级别的安全管控。这些还需要配套的安全服务提供支持。
一般来说,只要企业与互联网对接,那么随便一个面向消费者的「市场活动」,就有可能为企业带来井喷的流量。
传统企业内,更多的系统是管理信息类的支撑系统,这类系统在设计时的主要用户是企业内部员工以及有限的外部供应商。这类系统存在于企业内部的时间一直很长,功能耦合也很多,在功能解耦前,是非常不适合的,或者说绝对不可以直接为互联网的用户进行服务的。
SpringBoot自身并没有提供这样的流控措施,所以需要结合前面提到的S-EDA进行流量的控制,并结合下层的水平扩展能力(例如,Kubernets)进行流量负载合理的动态扩容。
另外,在长业务流程的设计上,也尽可能地采用异步的方式,比如接口调用返回的是一个「受理号」,而不是业务的处理结果,避免井喷业务到来时,同步调用所带来的阻塞导致系统迅速崩溃,这些也都是SpringBoot自身并不解决的问题。

5、总结

SpringBoot面试必备知识点 - 图17