SpringBoot常見的經典面試題

SpringBoot常見的經典面試題

最近很多人面試時,簡歷上都說自己熟悉 Spring Boot, 或者說正在學習Spring Boot,一被面試官問道,都只停留在簡單的使用階段,很多東西都不清楚,下面我整理了一些springboot比較常見的面試題

1、什麼是 Spring Boot?

Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡省了繁重xml的配置,提供了各種啓動器,在運行過程中自定配置, 開發者能快速上手。


2、爲什麼要用 Spring Boot?

Spring Boot 優點非常多,如:
獨立運行 簡化配置 自動配置 無代碼生成和XML配置 無需部署war文件


3、Spring Boot 的核心配置文件有哪幾個?它們的區別是什麼?

Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。

application 配置文件這個容易理解,主要用於 Spring Boot 項目的自動化配置。

bootstrap 配置文件有以下幾個應用場景。

  1. 使用SpringCloudConfig配置中心時,這時需要在 bootstrap 配置文件中添加連接到配置中心的配置屬性來加載外部配置中心的配置信息;
  2. 一些固定的不能被覆蓋的屬性;
  3. 一些加密/解密的場景;

4、Spring Boot 的配置文件有哪幾種格式?它們有什麼區別?

.properties 和 .yml,它們的區別主要是書寫格式不同。

1).properties

	app.user.name = javastack

2).yml

app:
 user:
    name: javastack

另外,.yml 格式不支持 @PropertySource 註解導入配置。


5、SpringBoot的核心註解是哪個?它主要由哪幾個註解組成的?

啓動類上面的註解是@SpringBootApplication,它也是 Spring Boot 的核心註解,主要組合包含了以下 3 個註解:

@SpringBootConfiguration:組合了 @Configuration 註解,實現配置文件的功能。
@EnableAutoConfiguration:打開自動配置的功能,也可以關閉某個自動配置的選項,如關閉數據源自動配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring組件掃描。


6、開啓SpringBoot特性有哪幾種方式?

1)繼承spring-boot-starter-parent項目

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.6.RELEASE</version>
</parent>

2)導入spring-boot-dependencies項目依賴

<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-dependencies</artifactId>
           <version>1.5.6.RELEASE</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
</dependencyManagement>

This only works if your Maven project inherits (directly or indirectly) from spring-boot-dependencies. If you have added spring-boot-dependencies in your own dependencyManagement section with import you have to redefine the artifact yourself instead of overriding the property.

Spring Boot依賴包裏面的組件的版本都是和當前Spring Boot綁定的,如果要修改裏面組件的版本,只需要添加如下屬性覆蓋即可,但這種方式只對繼承有效,導入的方式無效。

<properties>
   <slf4j.version>1.7.25<slf4j.version>
</properties>

如果導入的方式要實現版本的升級,達到上面的效果,這樣也可以做到,把要升級的組件依賴放到Spring Boot之前。

<dependencyManagement>
   <dependencies>
       <!-- Override Spring Data release train provided by Spring Boot -->
       <dependency>
           <groupId>org.springframework.data</groupId>
           <artifactId>spring-data-releasetrain</artifactId>
           <version>Fowler-SR2</version>
           <scope>import</scope>
           <type>pom</type>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-dependencies</artifactId>
           <version>1.5.6.RELEASE</version>
           <type>pom</type>
           <scope>import</scope>
       </dependency>
   </dependencies>
</dependencyManagement>

7、SpringBoot需要獨立的容器運行嗎?

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


8、運行SpringBoot有哪幾種方式?

1)打包用命令或者放到容器中運行

2)用 Maven/ Gradle 插件運行

3)直接執行 main 方法運行


9、Spring Boot 自動配置原理是什麼?

註解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自動配置的核心,首先它得是一個配置文件,其次根據類路徑下是否有這個類去自動配置。

Spring Boot的自動配置註解是@EnableAutoConfiguration, 從上面的@Import的類可以找到下面自動加載自動配置的映射。

 org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames(Class<?>, ClassLoader)
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
  String factoryClassName = factoryClass.getName();
  try {
     Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
              lassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      List<String> result = new ArrayList<String>();
      while (urls.hasMoreElements()) {
          URL url = urls.nextElement();
          Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
          String factoryClassNames = properties.getProperty(factoryClassName);
          result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
      }
      return result;
  }
  catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
              "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
  }

}

這個方法會加載類路徑及所有jar包下META-INF/spring.factories配置中映射的自動配置的類。

/**
* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
查看Spring Boot自帶的自動配置的包: spring-boot-autoconfigure-1.5.6.RELEASE.jar,打開其中的META-INF/spring.factories文件會找到自動配置的映射。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
...

再來看看數據源自動配置的實現註解

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
...
@Configuration,@ConditionalOnClass就是自動配置的核心,首先它得是一個配置文件,其次根據類路徑下是否有這個類去自動配置。

10、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 的各項能力,如自動配置、組件掃描等。


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

Starters可以理解爲啓動器,它包含了一系列可以集成到應用裏面的依賴包,你可以一站式集成 Spring 及其他技術,而不需要到處找示例代碼和依賴包。如你想使用 Spring JPA 訪問數據庫,只要加入 spring-boot-starter-data-jpa 啓動器依賴就能使用了。

Starters包含了許多項目中需要用到的依賴,它們能快速持續的運行,都是一系列得到支持的管理傳遞性依賴。具體請看這篇文章《Spring Boot Starters啓動器》。


12、如何在 Spring Boot 啓動的時候運行一些特定的代碼?

可以實現接口 ApplicationRunner 或者 CommandLineRunner,這兩個接口實現方式一樣,它們都只提供了一個 run 方法,具體請看這篇文章《Spring Boot Runner啓動器》。


13、Spring Boot 有哪幾種讀取配置的方式?

Spring Boot 可以通過 @PropertySource,@Value,@Environment, @ConfigurationProperties 來綁定變量,具體請看這篇文章《Spring Boot讀取配置的幾種方式》。

讀取application文件

在application.yml或者properties文件中添加:

info.address=USA
info.company=Spring
info.degree=high

@Value註解讀取方式

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
@Component
public class InfoConfig1 {
 
   @Value("${info.address}")
   private String address;
 
   @Value("${info.company}")
   private String company;
 
   @Value("${info.degree}")
   private String degree;
 
   public String getAddress() {
       return address;
   }
 
   public void setAddress(String address) {
       this.address = address;
   }
 
   public String getCompany() {
       return company;
   }
 
   public void setCompany(String company) {
       this.company = company;
   }
 
   public String getDegree() {
       return degree;
   }
 
   public void setDegree(String degree) {
       this.degree = degree;
   }
 
}

@ConfigurationProperties註解讀取方式

@Component
@ConfigurationProperties(prefix = "info")
public class InfoConfig2 {
 
   private String address;
   private String company;
   private String degree;
 
   public String getAddress() {
       return address;
   }
 
   public void setAddress(String address) {
       this.address = address;
   }
 
   public String getCompany() {
       return company;
   }
 
   public void setCompany(String company) {
       this.company = company;
   }
 
   public String getDegree() {
       return degree;
   }
 
   public void setDegree(String degree) {
       this.degree = degree;
   }
 
}

讀取指定文件
資源目錄下建立config/db-config.properties:

db.username=root
db.password=123456
@PropertySource+@Value註解讀取方式

@Component
@PropertySource(value = { "config/db-config.properties" })
public class DBConfig1 {
 
   @Value("${db.username}")
   private String username;
 
   @Value("${db.password}")
   private String password;
 
   public String getUsername() {
       return username;
   }
 
   public void setUsername(String username) {
       this.username = username;
   }
 
   public String getPassword() {
       return password;
   }
 
   public void setPassword(String password) {
       this.password = password;
   }
 
}
注意:@PropertySource不支持yml文件讀取。

@PropertySource+@ConfigurationProperties註解讀取方式

@Component
@ConfigurationProperties(prefix = "db")
@PropertySource(value = { "config/db-config.properties" })
public class DBConfig2 {
 
   private String username;
   private String password;
 
   public String getUsername() {
       return username;
   }
 
   public void setUsername(String username) {
       this.username = username;
   }
 
   public String getPassword() {
       return password;
   }
 
   public void setPassword(String password) {
       this.password = password;
   }
 
}

Environment讀取方式 以上所有加載出來的配置都可以通過Environment注入獲取到。

@Autowired
private Environment env;
 
// 獲取參數
String getProperty(String key);

14、Spring Boot 支持哪些日誌框架?推薦和默認的日誌框架是哪個?

Spring Boot 支持 Java Util Logging, Log4j2, Lockback 作爲日誌框架,如果你使用 Starters 啓動器,Spring Boot 將使用 Logback 作爲默認日誌框架,Spring Boot支持Java Util Logging,Log4j2,Lockback作爲日誌框架,如果你使用starters啓動器,Spring Boot將使用Logback作爲默認日誌框架。無論使用哪種日誌框架,Spring Boot都支持配置將日誌輸出到控制檯或者文件中。

spring-boot-starter啓動器包含spring-boot-starter-logging啓動器並集成了slf4j日誌抽象及Logback日誌框架。


15、SpringBoot 實現熱部署有哪幾種方式?

主要有兩種方式:

Spring Loaded

Spring-boot-devtools


16、你如何理解 Spring Boot 配置加載順序?

在 Spring Boot 裏面,可以使用以下幾種方式來加載配置。

1)properties文件;

2)YAML文件;

3)系統環境變量;

4)命令行參數;

配置屬性加載的順序如下:
1、開發者工具 Devtools 全局配置參數;
2、單元測試上的 @TestPropertySource 註解指定的參數;
3、單元測試上的 @SpringBootTest 註解指定的參數;
4、命令行指定的參數,如 java -jar springboot.jar --name="Java技術棧"
5、命令行中的 SPRING_APPLICATION_JSON 指定參數, 如 java -Dspring.application.json='{"name":"Java技術棧"}' -jar springboot.jar
6、ServletConfig 初始化參數;
7、ServletContext 初始化參數;
8、JNDI參數(如 java:comp/env/spring.application.json);
9、Java系統參數(來源:System.getProperties());
10、操作系統環境變量參數;
11、RandomValuePropertySource 隨機數,僅匹配:ramdom.*
12、JAR包外面的配置文件參數(application-{profile}.properties(YAML)
13、JAR包裏面的配置文件參數(application-{profile}.properties(YAML)
14、JAR包外面的配置文件參數(application.properties(YAML)
15、JAR包裏面的配置文件參數(application.properties(YAML)
16、@Configuration配置文件上 @PropertySource 註解加載的參數;
17、默認參數(通過 SpringApplication.setDefaultProperties 指定);

數字小的優先級越高,即數字小的會覆蓋數字大的參數值,我們來實踐下,驗證以上配置參數的加載順序。

1、在主應用程序中添加 Java 系統參數。

@Bean
public CommandLineRunner commandLineRunner() {
    return (args) -> {
        System.setProperty("name", "javastack-system-properties");
    };
}

2、在 application.properties 文件中添加屬性。

name = javastack-application

3、在 application-dev.properties 文件中添加屬性。

name = javastack-application-dev

4、添加測試類

@RunWith(SpringRunner.class)
@SpringBootTest(value = { "name=javastack-test", "sex=1" })
@ActiveProfiles("dev")
public class SpringBootBestPracticeApplicationTests {
 
    @Value("${name}")
    private String name;
 
    @Test
    public void test() {
        System.out.println("name is " + name);
    }
 
}

運行 test 單元測試,程序輸出:
name is javastack-test

根據以上參數動態調整,發現參數會被正確覆蓋。瞭解了 Spring Boot 各種配置的加載順序,如果配置被覆蓋了我們就知道是什麼問題了。


17、Spring Boot 如何定義多套不同環境配置?

提供多套配置文件,如:

applcation.properties

application-dev.properties
application-test.properties
application-prod.properties


18、Spring Boot 可以兼容老 Spring 項目嗎,如何做?

可以兼容,使用 @ImportResource 註解導入老 Spring 項目配置文件。

19、保護 Spring Boot 應用有哪些方法?

  1. 在生產中使用HTTPS

  2. 使用Snyk檢查你的依賴關係

  3. 升級到最新版本

  4. 啓用CSRF保護

  5. 使用內容安全策略防止XSS攻擊


20、Spring Boot 2.X 有什麼新特性?與 1.X 有什麼區別?

1. 配置變更
2. JDK 版本升級
3. 第三方類庫升級
4. 響應式 Spring 編程支持
5. HTTP/2 支持
6. 配置屬性綁定

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章