如此簡單的 SpringBoot,不瞭解一下

TimberLiu發表於2019-04-17

最近在學習了 Spring Boot 後,也用它寫了一個簡單的專案,真的發現它對使用 Spring 開發的人來說是一大福音,無需在像以前那樣需要配置很多東西。這篇文章,就結合一些常見的面試題和開發中會用到的,對 Spring Boot 來總結一下。

一、Spring Boot 是什麼

Spring Boot,看這個名字,就可以猜出來它是一個快速啟動 Spring 的框架,其實也正是如此,它採用“約定大於配置”的理念,提供了大量的自動配置,而無須再去編寫模板化的配置檔案,可以快速地建立一個可以獨立執行的 Spring 專案。

除了自動配置特性之外,它還有以下特性:

starter 啟動器

它提供了很多框架的 starter 啟動器,來簡化 maven 的依賴管理。Spring 專案中,在匯入其他框架的依賴時,還需要匯入其他附屬的依賴,如果框架比較多,那就會比較難以管理。而 Spring Boot 中提供了各種 starter 啟動器,可以對其進行很好的管理。例如,匯入 spring-boot-starter-web 依賴後,會自動新增如下依賴:

如此簡單的 SpringBoot,不瞭解一下

內嵌 Servlet 容器

它內嵌了很多 Servlet 容器,可以選擇 TomcatJetty 等。這樣就無須先下載 Tomcat,搭建好執行環境,再以 war 包的形式進行部署,而是可以直接以 jar 包的形式,通過 java -jar xxx.jar 去獨立執行。

準生產環境的應用監控

提供了準生產環境的應用監控。可以基於 HTTPJMXSSH 等對執行時的專案進行監控。對 Actuator 還不太瞭解,後續再進行補充。

二、Spring、SpringBoot、SpringCloud

很多人應該都聽說過這三個東西,那它們之間到底有什麼區別呢?

學過 Spring 的應該都知道這樣一句話,Spring 是一個 JavaSE/EE 一站式的輕量級開源框架。其中提供了很多模組,例如 IoCAOPMVCTest 等。SpringMVC 只是其中的一個模組。

SpringBoot 是基於 Spring 的一個 Boot 啟動器,為了更容易、更快速地搭建一個 Spring 專案。針對的是單體應用。

SpringCloud 則是微服務架構下的一個綜合性解決方案,對使用 SpringBoot 開發的一個個服務進行管理,它整合了許多基礎元件,來解決業務拆分後帶來的如配置管理、服務治理、容錯等問題。

三、Spring Boot 的啟動方式

Spring Boot 的啟動方式主要有三種,下面就分別來看一下:

1. 打成 jar 包

前面說了 Spring Boot 中內建了 Serlvet 容器,可以直接使用 java -jar xxx.jar。目前也推薦使用這種方式。另外通過這種方式,也可以在執行時指定一些引數。

pom.xml 檔案中,引入 spring-boot-maven-plugin 外掛後:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
複製程式碼

可以執行 mvn clean package 命令,將其打包成一個 jar 包,然後就可以通過 jar -jar xxx.jar 命令執行。

2. 執行 main 方法

Spring Boot 專案都會有一個主類,可以通過執行該類的 main 方法來啟動。這比較適用於開發除錯的時候。

3. 打成 war 包

如果是 web 專案,也可以打成 war 包,然後使用外部的 Tomcat 容器。

四、配置檔案

雖然 Spring Boot 提供了一系列自動化配置,來簡化繁重的配置。但是我們也要了解如何來修改這些預設配置,來適應一些特殊需求的場景。

4.1 配置方式

目前 Spring Boot 支援兩種配置方式,一種是傳統的 properties 檔案,以 key=value 形式來表示。例如,要修改預設的埠:

server.port=8081
複製程式碼

另一種是目前比較推薦使用的 YAML 檔案。它是以縮排的形式來表示,其結構更加地清晰易讀。例如:

server:
  port: 8081
複製程式碼

另外,YAML 檔案也支援在同一個檔案中通過 spring.profiles 屬性來定義多個不同的環境的配置。例如,在下面的檔案中:

server:
  port: 8080
---
server:
  port: 8081
spring:
  profiles: prod
--- 
server:
  port: 8082
spring:
  profiles: test
複製程式碼

如果我們指定為 test 環境,server.port 就使用 8082 埠;如果指定為 prod 環境,就使用 8081 埠,否則沒有指定的話,就使用 8080 埠。

但是 YAML 檔案有一些不足,它不能通過 @PropertySource 註解來載入指定的 YAML 配置檔案。不過可以通過 @Value 註解。

更多關於 YAML 的詳細語法,可以參考:阮一峰:YAML 語言教程

4.2 配置讀取方式

對於自定義的配置,要應用到我們的專案當中,SpringBoot 目前支援兩種讀取方式。它們也都支援和 @PropertySource 配合,來指定使用的配置檔案。

1. @Value

一種是剛才提到的 @Value,讀取配置到具體的屬性上。

例如,在 application.yml 檔案中新增如下配置:

user:
  name: TimberLiu
  age: 21
  address: China
複製程式碼

User 類就可以按照如下的方式進行讀取:

@Component
@Setter
@Getter
public class User {
    @Value("${user.name}")
    public String name;
    
    @Value("${user.age}")
    public int age;
    
    @Value("${user.address}")
    public String address;
}
複製程式碼

2. @ConfigurationProperties

另外一種是 @ConfigurationProperties,讀取配置到類上。

同樣是上面的配置內容,使用 @ConfigurationProperties 就可以像如下這樣配置:

@Component
@Setter
@Getter
@ConfigurationProperites(prefix="user")
public class User {

    public String name;
    public Integer age;
    public String address;
}
複製程式碼

3. 兩者的區別

那這兩種方式有什麼區別呢?通過下面這個表格來看一下:

/ @ConfigurationProperties @Value
功能 讀取配置到類上 讀取配置到屬性上
鬆散繫結 支援 不支援
JSR303 資料校驗 支援 不支援
複雜型別封裝 支援 不支援

下面通過一個例子來說明,例如對於下面的配置內容:

person:
  name: timberliu
  age: 21
  birthday: 2019/4/17
  info: {k1: v1,k2: v2}
  lists:
    - jack
    - rose
  dog:
    last_name: wang # 屬性中的名,last_name 匹配 lastName,鬆散繫結
    age: 3
複製程式碼

使用 @ConfigurationProperties 可以如下配置:

@Component
@Getter
@Setter
@ConfigurationProperties("person")
@Validated
public class Person {
    // 非空校驗
    @NotNull
    private String name;
    private Integer age;
    // 日期型別,資料校驗
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private Date birthday;
    // 複雜型別
    private Map<String, String> info;
    private List<Object> lists;
    private Dog dog;
}

@Component
@Getter
@Setter
@ConfigurationProperties("person.dog")
public class Dog {

    private String lastName;
    private Integer age;
}
複製程式碼

4.3 多環境配置

一般來說,專案都會對於不同的環境使用不同的配置,在 Spring Boot 中,多環境配置的檔名需要滿足 application-{profile}.properties 或者 .yml 的格式,其中 profile 對應的環境標識。

至於具體哪個環境會被載入,需要在 application.properties 檔案中通過 spring.profiles.active 屬性進行設定。

例如,如果有三個環境的配置檔案:

application-dev.properties
application-test.properties
application-prod.properties
複製程式碼

application.properties 檔案中指定 spring.profiles.active=dev,就會載入 application-dev.properties 配置檔案中的內容。

一般在實際開發中,多環境的配置思路如下:

  • application.properties 檔案中配置一些通用的屬性,並設定 spring.profiles.active=dev,預設配置為開發環境。
  • application-{profile}.properties 檔案中去配置不同環境不同的內容。
  • 具體什麼環境,通過命令列的方式去啟用對應環境的配置。

4.4 配置載入順序

通過前面已經瞭解到,屬性可以在很多地方進行配置,例如 application.properties 或者 application-{profile}.properties 檔案中,命令列中等等。那麼為了能夠更合理地重寫各屬性的值,下面來看一下這些配置的載入順序是怎樣的。由於這裡載入順序非常多,這裡只列舉一些常用的:

  • 命令列指定的引數。例如 java -jar myapplication.jar --server.port=8081
  • Java 系統變數。
  • 通過 random.* 配置的隨機屬性。
  • Jar部的,針對不同 {profile} 環境的配置檔案內容,例如 application-{profile}.properties
  • Jar部的,針對不同 {profile} 環境的配置檔案內容,例如 application-{profile}.yml
  • Jar部的 application.propertiesapplication.yml
  • Jar部的 application.propertiesapplication.yml
  • 在自定義的 @Configuration 類中,通過 @PropetySource 註解定義的屬性。
  • 使用 SpringApplication.setDefaultProperties 定義的屬性。

這些載入順序,越往下優先順序越低。

五、最後

本文介紹了 Spring Boot 的基本概念。其中詳細說了 SpringBoot 的配置檔案,例如配置檔案的格式、讀取方式,多環境下應該如何配置,及配置檔案的載入順序。

下篇文章將詳細說一下 SpringBoot 的啟動方式和自動配置原理。

相關文章