(翻译)Spring Boot 面试题

1. 概述

自推出以来,Spring Boot一直是Spring生态系统中的一个重要角色。这个项目凭借其自动配置能力使我们的生活变得更加轻松。

在本教程中,我们将介绍一些在求职面试中可能出现的与Spring Boot有关的最常见问题。

2. 题目

Q1. 什么是Spring Boot,其主要特点是什么?

Spring Boot本质上是一个建立在Spring框架之上的快速应用开发框架。凭借其自动配置和嵌入式应用服务器支持,再加上其享有的大量文档和社区支持,Spring Boot是迄今为止Java生态系统中最受欢迎的技术之一。

这里有几个突出的特点。

  • 启动器 – 一组依赖性描述符,可以一次性包括相关的依赖性
  • 自动配置 – 一种基于classpath上的依赖关系自动配置应用程序的方法
  • 执行器 – 获得生产就绪的功能,如监控
  • 安全性
  • 记录

Q2. Spring和Spring Boot之间的区别是什么?

Spring框架提供了多种功能,使Web应用的开发更加容易。这些功能包括依赖性注入、数据绑定、面向方面的编程、数据访问等等。

多年来,Spring越来越复杂,这种应用所需的配置量可能令人生畏。这就是Spring Boot的用武之地–它使配置一个Spring应用程序变得轻而易举。

从本质上讲,Spring是没有主见的,而Spring Boot对平台和库有主见,让我们快速上手。

下面是Spring Boot带来的两个最重要的好处。

  • 根据它在classpath上找到的库自动配置应用程序
  • 提供生产中的应用程序常见的非功能特性,如安全或健康检查

请查看我们的其他教程,了解普通Spring和Spring Boot的详细比较

Q3. 我们如何用Maven设置Spring Boot应用程序?

我们可以像对待其他库一样,将Spring Boot纳入Maven项目中。不过,最好的方法是从spring-boot-starter-parent项目中继承,并声明对Spring Boot starters的依赖关系。这样做可以让我们的项目重用Spring Boot的默认设置。

继承spring-boot-starter-parent项目很简单,我们只需要在pom.xml中指定一个父元素:

1
2
3
4
5
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0.RELEASE</version>
</parent>

我们可以在Maven中心找到最新版本的spring-boot-starter-parent。

使用启动器父项目很方便,但并不总是可行的。例如,如果我们公司要求所有项目都继承自标准POM,那么我们仍然可以通过使用自定义父项目来受益于Spring Boot的依赖性管理。

Q4. 什么是Spring Initializr?

Spring Initializr是一种创建Spring Boot项目的便捷方式。

我们可以去Spring Initializr网站,选择一个依赖管理工具(Maven或Gradle)、一种语言(Java、Kotlin或Groovy)、一种打包方案(Jar或War)、版本和依赖性,然后下载项目。

这为我们创建了一个骨架项目,节省了设置时间,这样我们就可以集中精力添加业务逻辑。

即使我们使用IDE的(如STS或带有STS插件的Eclipse)新项目向导来创建Spring Boot项目,它也会在底下使用Spring Initializr。

Q5. 外面有哪些Spring Boot启动器?

每个启动器都扮演着一站式服务的角色,提供我们需要的所有 Spring 技术。其他所需的依赖项也会被拉进来,并以一致的方式进行管理。

所有启动器都在org.springframework.boot组下,其名称以spring-boot-starter-开头。这种命名模式使我们很容易找到启动器,特别是在使用支持按名称搜索依赖关系的IDE时。

在写这篇文章的时候,有超过50个启动器供我们使用。这里,我们将列出最常见的:

  • spring-boot-starter:核心启动器,包括自动配置支持、日志和YAML
  • spring-boot-starter-aop: 使用Spring AOP和AspectJ进行面向方面的编程
  • spring-boot-starter-data-jpa:用于在Hibernate中使用Spring Data JPA。
  • spring-boot-starter-security: 用于使用Spring Security。
  • spring-boot-starter-test: 用于测试Spring Boot应用程序
  • spring-boot-starter-web: 用于使用Spring MVC构建Web(包括RESTful)应用程序。

有关启动程序的完整列表,请参见该资源库

要找到关于Spring Boot启动程序的更多信息,请看Spring Boot启动程序介绍

Q6. 如何禁用一个特定的自动配置?

如果我们想禁用一个特定的自动配置,我们可以使用@EnableAutoConfiguration注解的exclude属性来设置它。

例如,这个代码片断禁用了DataSourceAutoConfiguration:

1
2
3
// other annotations
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
public class MyConfiguration { }

如果我们用@SpringBootApplication注解启用了自动配置–该注解将@EnableAutoConfiguration作为元注解–我们可以用同名的属性禁用自动配置:

1
2
3
// other annotations
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyConfiguration { }

我们也可以用spring.autoconfigure.exclude环境属性禁用自动配置。在application.properties文件中的配置与之前做的设置是做相同的事情:

1
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

Q7. 如何注册一个自定义的自动配置?

要注册一个自动配置类,我们必须在META-INF/spring.factories文件的EnableAutoConfiguration键下列出其完全限定名称:

1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.baeldung.autoconfigure.CustomAutoConfiguration

如果我们用Maven构建项目,该文件应放在resources/META-INF目录下,在打包阶段最终会出现在上述位置。

Q8. 如何告诉自动配置在Bean存在时退缩?

为了指示自动配置类在Bean已经存在时退缩,我们可以使用 @ConditionalOnMissingBean 注解。

这个注解最值得注意的属性是:

  • value – 要检查的Bean的类型
  • name – 要检查的bean的名字

当放在一个用@Bean装饰的方法上时,目标类型默认为该方法的返回类型:

1
2
3
4
5
6
@Configuration
public class CustomConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public CustomService service() { ... }
}

Q9. 如何将Spring Boot Web应用部署为Jar和War文件?

传统上,我们将Web应用打包成WAR文件,然后将其部署到外部服务器上。这样做可以让我们在同一台服务器上安排多个应用程序。在CPU和内存稀缺的时候,这是一个节省资源的好方法。

但事情已经发生了变化。现在计算机硬件相当便宜,人们的注意力已经转向服务器配置。在部署过程中,配置服务器的一个小错误可能会导致灾难性的后果。

Spring通过提供一个插件,即spring-boot-maven-plugin,将网络应用打包成可执行的JAR,来解决这个问题。

要包含这个插件,只需在pom.xml中添加一个插件元素:

1
2
3
4
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

有了这个插件,我们在执行打包阶段后会得到一个扁平的JAR。这个JAR包含所有必要的依赖,包括一个嵌入式服务器。因此,我们不再需要担心配置外部服务器的问题。

然后我们可以像运行普通的可执行JAR一样运行该应用程序。

注意,pom.xml文件中的打包元素必须设置为jar来构建JAR文件:

1
<packaging>jar</packaging>

如果我们不包括这个元素,它也默认为jar。

要构建一个WAR文件,我们把包装元素改为war:

1
<packaging>war</packaging>

并将容器的依赖关系从打包的文件中删除:

1
2
3
4
5
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

在执行Maven打包阶段后,我们会有一个可部署的WAR文件。

Q10. 如何在命令行应用程序中使用Spring Boot?

就像其他Java程序一样,Spring Boot命令行应用程序必须有一个main方法。

这个方法作为一个入口点,它调用SpringApplication#run方法来启动应用程序:

1
2
3
4
5
6
7
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class);
        // other statements
    }
}

然后SpringApplication类启动Spring容器并自动配置Bean。

注意我们必须向run方法传递一个配置类,作为主要的配置源。按照惯例,这个参数就是入口类本身。

在调用运行方法后,我们可以像普通程序一样执行其他语句。

Q11. 外部配置的可能来源是什么?

Spring Boot提供了对外部配置的支持,使我们能够在不同的环境中运行同一个应用程序。我们可以使用属性文件、YAML文件、环境变量、系统属性和命令行选项参数来指定配置属性。

然后,我们可以使用@Value注解、通过@ConfigurationProperties注解的绑定对象或环境抽象来访问这些属性。

Q12. Spring Boot支持宽松的绑定是什么意思?

Spring Boot中的宽松绑定适用于配置属性的类型安全绑定

通过宽松的绑定,属性的键不需要与属性名完全匹配。这样的环境属性可以用camelCase、kebab-case、snake_case,或者用大写字母,用下划线隔开单词。

例如,如果一个带有 @ConfigurationProperties 注解的 bean 类中的一个属性被命名为 myProp,它可以被绑定到这些环境属性中的任何一个:myProp、my-prop、my_prop 或 MY_PROP。

Q13. Spring Boot DevTools的用途是什么?

Spring Boot开发者工具,或称DevTools,是一套使开发过程更容易的工具。

为了包括这些开发时的功能,我们只需要在pom.xml文件中添加一个依赖项:

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

如果应用程序在生产中运行,spring-boot-devtools模块会自动禁用。重新打包的归档文件也默认排除了这个模块。所以,它不会给我们的最终产品带来任何开销。

默认情况下,DevTools应用适合于开发环境的属性。这些属性禁用了模板缓存,启用了网络组的调试日志,诸如此类。因此,我们有了这种合理的开发时配置,而无需设置任何属性。

只要classpath上的文件发生变化,使用DevTools的应用程序就会重新启动。这在开发中是一个非常有帮助的功能,因为它可以快速反馈修改情况。

默认情况下,静态资源,包括视图模板,不会引发重启。相反,资源变化会触发浏览器刷新。请注意,只有在浏览器中安装了LiveReload扩展,以便与DevTools包含的嵌入式LiveReload服务器进行交互时,这才会发生。

关于这一主题的进一步信息,请参见Spring Boot DevTools概述

Q14. 如何编写集成测试?

在为Spring应用程序运行集成测试时,我们必须有一个ApplicationContext。

为了让我们的生活更轻松,Spring Boot为测试提供了一个特殊的注解–@SpringBootTest。该注解从其classes属性所指示的配置类中创建一个ApplicationContext。

如果classes属性没有设置,Spring Boot会搜索主要的配置类。搜索从包含测试的包开始,直到找到一个用@SpringBootApplication或@SpringBootConfiguration注解的类。

有关详细说明,请查看我们的Spring Boot测试教程

Q15. Spring Boot Actuator的用途是什么?

从本质上讲,Actuator通过启用生产就绪的功能,使Spring Boot应用程序活起来。这些功能使我们能够在应用程序在生产中运行时监控和管理它们。

将Spring Boot Actuator集成到一个项目中非常简单。我们所要做的就是在pom.xml文件中包括spring-boot-starter-actuator启动器:

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Spring Boot Actuator可以使用HTTP或JMX端点来暴露操作信息。但大多数应用程序都会选择HTTP,其中端点的身份和/actuator前缀构成了一个URL路径。

下面是Actuator提供的一些最常见的内置端点。

  • env 暴露环境属性
  • health 显示应用程序的健康信息
  • httptrace 显示HTTP跟踪信息
  • info 显示任意的应用程序信息
  • metrics 显示度量信息
  • loggers 显示并修改应用程序中的记录器配置
  • mappings 显示所有@RequestMapping路径的列表

请参考我们的Spring Boot Actuator教程,了解详细情况。

Q16. 配置Spring Boot项目时,属性和YAML哪个更好?

与属性文件相比,YAML有很多优点。

  • 更加清晰,可读性更好
  • 非常适合分层的配置数据,也可以用更好、更易读的格式来表示
  • 支持地图、列表和标量类型
  • 可以在同一个文件中包含多个配置文件(从Spring Boot 2.4.0开始,属性文件也可以这样做了)

但是,由于它的缩进规则,编写它可能有点困难,而且容易出错。

有关细节和工作样本,请参考我们的Spring YAML与属性教程。

Q17. Spring Boot提供了哪些基本注解?

Spring Boot提供的主要注释位于org.springframework.boot.autoconfigure及其子包中。

以下是一些基本的注释:

  • @EnableAutoConfiguration – 使Spring Boot在其classpath上寻找自动配置豆并自动应用它们。
  • @SpringBootApplication – 表示Boot Application的主类。该注解将@Configuration、@EnableAutoConfiguration和@ComponentScan注解与它们的默认属性结合起来。

Spring Boot注解提供了对这一主题的更多见解。

Q18. 如何改变Spring Boot中的默认端口?

我们可以通过以下方式改变嵌入Spring Boot中的服务器的默认端口。

  • 使用属性文件 – 我们可以在application.properties(或application.yml)文件中使用属性server.port来定义。
  • 通过编程 – 在我们的主@SpringBootApplication类中,我们可以在SpringApplication实例上设置server.port。
  • 使用命令行 – 当以jar文件的形式运行应用程序时,我们可以将server.port设置为java命令参数:
1
java -jar -Dserver.port=8081 myspringproject.jar

Q19. Spring Boot支持哪些嵌入式服务器,以及如何改变默认值?

截至目前,Spring MVC支持Tomcat、Jetty和Undertow。Tomcat是Spring Boot的Web Starter支持的默认应用服务器。

Spring WebFlux支持Reactor Netty、Tomcat、Jetty和Undertow,其中Reactor Netty为默认。

在Spring MVC中,如果要改变默认,比方说改变为Jetty,我们需要排除Tomcat,在依赖关系中包括Jetty:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

同样,要把WebFlux的默认值改为UnderTow,我们需要排除Reactor Netty,并把UnderTow纳入依赖关系。

比较Spring Boot中的嵌入式Servlet容器有更多关于我们可以在Spring MVC中使用的不同嵌入式服务器的细节。

Q20. 为什么我们需要Spring Profiles?

在为企业开发应用程序时,我们通常要处理多种环境,如开发、QA和生产。这些环境的配置属性是不同的。

例如,我们可能在开发中使用嵌入式H2数据库,但开发中可能有专有的Oracle或DB2。即使DBMS在不同的环境中是相同的,URLs也肯定是不同的。

为了使这个问题简单明了,Spring提供了配置文件,以帮助分离每个环境的配置。因此,可以将这些属性保存在不同的文件中,如application-dev.properties和application-prod.properties,而不是通过编程来维护这些属性。默认的application.properties使用spring.profiles.active指向当前活动的配置文件,这样就可以获得正确的配置。

Spring Profiles给出了关于这个主题的全面观点。

3. 总结

本文介绍了技术面试中可能出现的关于Spring Boot的一些最关键问题。

我们希望这些问题能够帮助你找到理想的工作。

4. 原文