讀古今文學網 > Spring Boot實戰 > 3.2 通過屬性文件外置配置 >

3.2 通過屬性文件外置配置

在處理應用安全時,你當然會希望完全掌控所有配置。不過,為了微調一些細節,比如改改端口號和日誌級別,便放棄自動配置,這是一件讓人羞愧的事。為了設置數據庫URL,是配置一個屬性簡單,還是完整地聲明一個數據源的Bean簡單?答案不言自明,不是嗎?

事實上,Spring Boot自動配置的Bean提供了300多個用於微調的屬性。當你調整設置時,只要在環境變量、Java系統屬性、JNDI(Java Naming and Directory Interface)、命令行參數或者屬性文件裡進行指定就好了。

要瞭解這些屬性,讓我們來看個非常簡單的例子。你也許已經注意到了,在命令行裡運行閱讀列表應用程序時,Spring Boot有一個ascii-art Banner。如果你想禁用這個Banner,可以將spring.main.show-banner屬性設置為false。有幾種實現方式,其中之一就是在運行應用程序的命令行參數里指定:

$ java -jar readinglist-0.0.1-SNAPSHOT.jar --spring.main.show-banner=false

  

另一種方式是創建一個名為application.properties的文件,包含如下內容:

spring.main.show-banner=false

  

或者,如果你喜歡的話,也可以創建名為application.yml的YAML文件,內容如下:

spring:
  main:
    show-banner: false

  

還可以將屬性設置為環境變量。舉例來說,如果你用的是bash或者zsh,可以用export命令:

$ export spring_main_show_banner=false

  

請注意,這裡用的是下劃線而不是點和橫槓,這是對環境變量名稱的要求。

實際上,Spring Boot應用程序有多種設置途徑。Spring Boot能從多種屬性源獲得屬性,包括如下幾處。

(1) 命令行參數

(2) java:comp/env裡的JNDI屬性

(3) JVM系統屬性

(4) 操作系統環境變量

(5) 隨機生成的帶random.*前綴的屬性(在設置其他屬性時,可以引用它們,比如${random.long}

(6) 應用程序以外的application.properties或者appliaction.yml文件

(7) 打包在應用程序內的application.properties或者appliaction.yml文件

(8) 通過@PropertySource標注的屬性源

(9) 默認屬性

這個列表按照優先級排序,也就是說,任何在高優先級屬性源裡設置的屬性都會覆蓋低優先級的相同屬性。例如,命令行參數會覆蓋其他屬性源裡的屬性。

application.properties和application.yml文件能放在以下四個位置。

(1) 外置,在相對於應用程序運行目錄的/config子目錄裡。

(2) 外置,在應用程序運行的目錄裡。

(3) 內置,在config包內。

(4) 內置,在Classpath根目錄。

同樣,這個列表按照優先級排序。也就是說,/config子目錄裡的application.properties會覆蓋應用程序Classpath裡的application.properties中的相同屬性。

此外,如果你在同一優先級位置同時有application.properties和application.yml,那麼application.yml裡的屬性會覆蓋application.properties裡的屬性。

禁用ascii-art Banner只是使用屬性的一個小例子。讓我們再看幾個例子,看看如何通過常用途徑微調自動配置的Bean。

3.2.1 自動配置微調

如上所說,有300多個屬性可以用來微調Spring Boot應用程序裡的Bean。附錄C有一個詳盡的列表。此處無法逐一描述它們的細節,因此我們就通過幾個例子來瞭解一些Spring Boot暴露的實用屬性。

1. 禁用模板緩存

如果閱讀列表應用程序經過了幾番修改,你一定已經注意到了,除非重啟應用程序,否則對Thymeleaf模板的變更是不會生效的。這是因為Thymeleaf模板默認緩存。這有助於改善應用程序的性能,因為模板只需編譯一次,但在開發過程中就不能實時看到變更的效果了。

spring.thymeleaf.cache設置為false就能禁用Thymeleaf模板緩存。在命令行裡運行應用程序時,將其設置為命令行參數即可:

$ java -jar readinglist-0.0.1-SNAPSHOT.jar --spring.thymeleaf.cache=false

  

或者,如果你希望每次運行時都禁用緩存,可以創建一個application.yml,包含以下內容:

spring:
  thymeleaf:
    cache: false

  

你一定要確保這個文件不會發佈到生產環境,否則生產環境裡的應用程序就無法享受模板緩存帶來的性能提升了。

作為開發者,在修改模板時始終關閉緩存實在太方便了。為此,可以通過環境變量來禁用Thymeleaf緩存:

$ export spring_thymeleaf_cache=false

  

此處使用Thymeleaf作為應用程序的視圖,Spring Boot支持的其他模板也能關閉模板緩存,設置這些屬性就好了:

  • spring.freemarker.cache(Freemarker)

  • spring.groovy.template.cache(Groovy模板)

  • spring.velocity.cache(Velocity)

默認情況下,這些屬性都為true,也就是開啟緩存。將它們設置為false即可禁用緩存。

2. 配置嵌入式服務器

從命令行(或者Spring Tool Suite)運行Spring Boot應用程序時,應用程序會啟動一個嵌入式的服務器(默認是Tomcat),監聽8080端口。大部分情況下這樣挺好,但同時運行多個應用程序可能會有問題。要是所有應用程序都試著讓Tomcat服務器監聽同一個端口,在啟動第二個應用程序時就會有衝突。

無論出於什麼原因,讓服務器監聽不同的端口,你所要做的就是設置server.port屬性。要是只改一次,可以用命令行參數:

$ java -jar readinglist-0.0.1-SNAPSHOT.jar --server.port=8000

  

但如果希望端口變更時間更長一點,可以在其他支持的配置位置上設置server.port。例如,把它放在應用程序Classpath根目錄的application.yml文件裡:

server:
  port: 8000

  

除了服務器的端口,你還可能希望服務器提供HTTPS服務。為此,第一步就是用JDK的keytool工具來創建一個密鑰存儲(keystore):

$ keytool -keystore mykeys.jks -genkey -alias tomcat -keyalg RSA

  

該工具會詢問幾個與名字和組織相關的問題,大部分都無關緊要。但在被問到密碼時,一定要記住你的選擇。在本例中,我選擇letmein作為密碼。

現在只需要設置幾個屬性就能開啟嵌入式服務器的HTTPS服務了。可以把它們都配置在命令行裡,但這樣太不方便了。可以把它們放在application.properties或application.yml裡。在application.yml中,它們可能是這樣的:

server:
  port: 8443
  ssl:
    key-store: file:///path/to/mykeys.jks
    key-store-password: letmein
    key-password: letmein

  

此處的server.port設置為8443,開發環境的HTTPS服務器大多會選這個端口。server.ssl.key-store屬性指向密鑰存儲文件的存放路徑。這裡用了一個file://開頭的URL,從文件系統裡加載該文件。你也可以把它打包在應用程序的JAR文件裡,用classpath: URL來引用它。server.ssl.key-store-passwordserver.ssl.key-password設置為創建該文件時給定的密碼。

有了這些屬性,應用程序就能在8443端口上監聽HTTPS請求了。(根據你所用的瀏覽器,可能會出現警告框提示該服務器無法驗證其身份。在開發時,訪問的是localhost,這沒什麼好擔心的。)

3. 配置日誌

大多數應用程序都提供了某種形式的日誌。即使你的應用程序不會直接記錄日誌,你所用的庫也會記錄它們的活動。

默認情況下,Spring Boot會用Logback(http://logback.qos.ch)來記錄日誌,並用INFO級別輸出到控制台。在運行應用程序和其他例子時,你應該已經看到很多INFO級別的日誌了。

用其他日誌實現替換Logback

一般來說,你不需要切換日誌實現;Logback能很好地滿足你的需要。但是,如果決定使用Log4j或者Log4j2,那麼你只需要修改依賴,引入對應該日誌實現的起步依賴,同時排除掉Logback。

以Maven為例,應排除掉根起步依賴傳遞引入的默認日誌起步依賴,這樣就能排除Logback了:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
    </exclusion>
  </exclusions>
</dependency>

  

在Gradle裡,在configurations下排除該起步依賴是最簡單的辦法:

configurations {
  all*.exclude group:'org.springframework.boot',
               module:'spring-boot-starter-logging'
}

  

排除默認日誌的起步依賴後,就可以引入你想用的日誌實現的起步依賴了。在Maven裡可以這樣添加Log4j:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-log4j</artifactId>
</dependency>

  

在Gradle裡可以這樣添加Log4j:

compile("org.springframework.boot:spring-boot-starter-log4j")

  

如果你想用Log4j2,可以把spring-boot-starter-log4j改成spring-boot-starter-log4j2。

要完全掌握日誌配置,可以在Classpath的根目錄(src/main/resources)裡創建logback.xml文件。下面是一個logback.xml的簡單例子:

<configuration>
  <appender name="STDOUT">
    <encoder>
      <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      </pattern>
    </encoder>
  </appender>

  <logger name="root" level="INFO"/>

  <root level="INFO">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

  

除了日誌格式之外,這個Logback配置和不加logback.xml文件的默認配置差不多。但是,通過編輯logback.xml,你可以完全掌控應用程序的日誌文件。哪些配置應該放進logback.xml這個話題不在本書的討論範圍內,請參考Logback的文檔以瞭解更多信息。

即使如此,你對日誌配置最常做的改動就是修改日誌級別和指定日誌輸出的文件。使用了Spring Boot的配置屬性後,你可以在不創建logback.xml文件的情況下修改那些配置。

要設置日誌級別,你可以創建以logging.level開頭的屬性,後面是要日誌名稱。如果根日誌級別要設置為WARN,但Spring Security的日誌要用DEBUG級別,可以在application.yml裡加入以下內容:

logging:
  level:
    root: WARN
    org:
      springframework:
        security: DEBUG

  

另外,你也可以把Spring Security的包名寫成一行:

logging:
  level:
    root: WARN
    org.springframework.security: DEBUG

  

現在,假設你想把日誌寫到位於/var/logs/目錄裡的BookWorm.log文件裡。使用logging.pathloggin.file屬性就行了:

logging:
  path: /var/logs/
  file: BookWorm.log
  level:
    root: WARN
    org:
      springframework:
        security: DEBUG

  

假設應用程序有/var/logs/的寫權限,日誌就能被寫入/var/logs/BookWorm.log。默認情況下,日誌文件的大小達到10MB時會切分一次。

與之類似,這些屬性也能在application.properties裡設置:

logging.path=/var/logs/
logging.file=BookWorm.log
logging.level.root=WARN
logging.level.root.org.springframework.security=DEBUG

  

如果你還是想要完全掌控日誌配置,但是又不想用logback.xml作為Logback配置的名字,可以通過logging.config屬性指定自定義的名字:

logging:
  config:
    classpath:logging-config.xml

  

雖然一般並不需要改變配置文件的名字,但是如果你想針對不同運行時Profile使用不同的日誌配置(見3.2.3節),這個功能會很有用。

4. 配置數據源

此時,我們還在開發閱讀列表應用程序,嵌入式的H2數據庫能很好地滿足我們的需要。可是一旦要投放到生產環境,我們可能要考慮更持久的數據庫解決方案。

雖然你可以顯式配置自己的DataSource Bean,但通常並不用這麼做,只需簡單地通過屬性配置數據庫的URL和身份信息就可以了。舉例來說,如果你用的是MySQL數據庫,你的application.yml文件看起來可能是這樣的:

spring:
  datasource:
    url: jdbc:mysql://localhost/readinglist
    username: dbuser
    password: dbpass

  

通常你都無需指定JDBC驅動,Spring Boot會根據數據庫URL識別出需要的驅動,但如果識別出問題了,你還可以設置spring.datasource.driver-class-name屬性:

spring:
  datasource:
    url: jdbc:mysql://localhost/readinglist
    username: dbuser
    password: dbpass
    driver-class-name: com.mysql.jdbc.Driver

  

在自動配置DataSource Bean的時候,Spring Boot會使用這裡的連接數據。DataSource Bean是一個連接池,如果Classpath裡有Tomcat的連接池DataSource,那麼就會使用這個連接池;否則,Spring Boot會在Classpath裡查找以下連接池:

  • HikariCP

  • Commons DBCP

  • Commons DBCP 2

這裡列出的只是自動配置支持的連接池,你還可以自己配置DataSource Bean,使用你喜歡的各種連接池。

你也可以設置spring.datasource.jndi-name屬性,從JNDI裡查找DataSource

spring:
  datasource:
    jndi-name: java:/comp/env/jdbc/readingListDS

  

一旦設置了spring.datasource.jndi-name屬性,其他數據源連接屬性都會被忽略,除非沒有設置別的數據源連接屬性。

有很多影響Spring Boot自動配置組件的方法,只需設置一兩個屬性即可。但這種配置外置的方法並不局限於Spring Boot配置的Bean。讓我們看看如何使用這種屬性配置機制來微調自己的應用程序組件。

3.2.2 應用程序Bean的配置外置

假設我們在某人的閱讀列表裡不止想要展示圖書標題,還要提供該書的Amazon鏈接。我們不僅想提供該書的鏈接,還要標記該書,以便利用Amazon的Associate Program,這樣如果有人用我們應用程序裡的鏈接買了書,我們還能收到一筆推薦費。

這很簡單,只需修改Thymeleaf模板,以鏈接的形式來呈現每本書的標題就可以了:

<a th:href="'http://www.amazon.com/gp/product/'
            + ${book.isbn}
            + '/tag=habuma-20'"
   th:text="${book.title}">Title</a>

  

這樣就好了。現在如果有人點擊該鏈接並購買了本書,我就能得到推薦費了,因為habuma-20是我的Amazon Associate ID。如果你也想收到推薦費,可以把Thymeleaf模板中tag的值改成你的Amazon Associate ID。

雖然在模板裡修改這個值很簡單,但這畢竟也是硬編碼。現在只在一個模板裡鏈接到Amazon,但後續可能會有更多頁面鏈接到Amazon,於是需要為應用程序添加功能。那樣的話,修改Amazon Associate ID就要改動好幾個地方。因此,這種細節最好不要放在代碼裡,要把它們集中在一個地方維護。

我們可以不在模板裡硬編碼Amazon Associate ID,而是把它變成模型中的一個值:

<a th:href="'http://www.amazon.com/gp/product/'
            + ${book.isbn}
            + '/tag=' + ${amazonID}"
   th:text="${book.title}">Title</a>

  

此外,ReadingListController需要在模型裡包含amazonID這個鍵,其中的內容是Amazon Associate ID。同樣的道理,我們不應該硬編碼這個值,而是應該引用一個實例變量。這個變量的值應該來自屬性配置。代碼清單3-4就是新的ReadingListController,它會返回注入的Amazon Associate ID。

代碼清單3-4 修改後的ReadingListController,能接受Amazon ID

package readinglist;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/")
@ConfigurationProperties(prefix="amazon")        ←---屬性注入
public class ReadingListController {

  private String associateId;

  private ReadingListRepository readingListRepository;

  @Autowired
  public ReadingListController(
        ReadingListRepository readingListRepository) {
    this.readingListRepository = readingListRepository;
  }

  public void setAssociateId(String associateId) {     ←---associateId的setter方法
    this.associateId = associateId;
  }

  @RequestMapping(method=RequestMethod.GET)
  public String readersBooks(Reader reader, Model model) {
    List<Book> readingList =
               readingListRepository.findByReader(reader);
    if (readingList != null) {
      model.addAttribute("books", readingList);
      model.addAttribute("reader", reader);
      model.addAttribute("amazonID", associateId);     ←---將associateId放入模型
    }
    return "readingList";
  }

  @RequestMapping(method=RequestMethod.POST)
  public String addToReadingList(Reader reader, Book book) {
    book.setReader(reader);
    readingListRepository.save(book);
    return "redirect:/";
  }

}

  

如你所見,ReadingListController現在有了一個associateId屬性,還有對應的setAssociateId方法,用它可以設置該屬性。readersBooks現在能通過amazonID這個鍵把associateId的值放入模型。

棒極了!現在就剩一個問題了——從哪裡能取到associateId的值。

請注意,ReadingListController上加了@ConfigurationProperties註解,這說明該Bean的屬性應該是(通過setter方法)從配置屬性值注入的。說得更具體一點,prefix屬性說明ReadingListController應該注入帶amazon前綴的屬性。

綜合起來,我們指定ReadingListController的屬性應該從帶amazon前綴的配置屬性中進行注入。ReadingListController只有一個setter方法,就是設置associateId屬性用的setter方法。因此,設置Amazon Associate ID唯一要做的就是添加amazon.associateId屬性,把它加入支持的任一屬性源位置裡即可。

例如,我們可以在application.properties裡設置該屬性:

amazon.associateId=habuma-20

 

或者在application.yml裡設置:

amazon:
  associateId: habuma-20

  

或者,我們可以將其設置為環境變量,把它作為命令行參數,或把它加到任何能夠設置配置屬性的地方。

開啟配置屬性 從技術上來說,@ConfigurationProperties註解不會生效,除非先向Spring配置類添加@EnableConfigurationProperties註解。但通常無需這麼做,因為Spring Boot自動配置後面的全部配置類都已經加上了@EnableConfigurationProperties註解。因此,除非你完全不使用自動配置(那怎麼可能?),否則就無需顯式地添加@EnableConfigurationProperties

還有一點需要注意,Spring Boot的屬性解析器非常智能,它會自動把駝峰規則的屬性和使用連字符或下劃線的同名屬性關聯起來。換句話說,amazon.associateId這個屬性和amazon.associate_id以及amazon.associate-id都是等價的。用你習慣的命名規則就好。

在一個類裡收集屬性

雖然在ReadingListController上加上@ConfigurationProperties註解跑起來沒問題,但這並不是一個理想的方案。ReadingListController和Amazon沒什麼關係,但屬性的前綴卻是amazon,這看起來難道不奇怪嗎?再說,後續的各種功能可能需要在ReadingListController裡新增配置屬性,而它們和Amazon無關。

與其在ReadingListController裡加載配置屬性,還不如創建一個單獨的Bean,為它加上@ConfigurationProperties註解,讓這個Bean收集所有配置屬性。代碼清單3-5里的AmazonProperties就是一個例子,它用於加載Amazon相關的配置屬性。

代碼清單3-5 在一個Bean裡加載配置屬性

package readinglist;

import org.springframework.boot.context.properties.
                                   ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("amazon")      ←---注入帶amazon前綴的屬性
public class AmazonProperties {

  private String associateId;

  public void setAssociateId(String associateId) {     ←---associateId的setter方法
    this.associateId = associateId;
  }

  public String getAssociateId {
    return associateId;
  }

}

  

有了加載amazon.associateId配置屬性的AmazonProperties後,我們可以調整ReadingListController(如代碼清單3-6所示),讓它從注入的AmazonProperties中獲取Amazon Associate ID。

代碼清單3-6 注入了AmazonPropertiesReadingListController

package readinglist;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/")
public class ReadingListController {

  private ReadingListRepository readingListRepository;
  private AmazonProperties amazonProperties;

  @Autowired
  public ReadingListController(
      ReadingListRepository readingListRepository,
      AmazonProperties amazonProperties) {    ←---注入AmazonProperties
    this.readingListRepository = readingListRepository;
    this.amazonProperties = amazonProperties;
  }

  @RequestMapping(method=RequestMethod.GET)
  public String readersBooks(Reader reader, Model model) {
    List<Book> readingList =
        readingListRepository.findByReader(reader);
    if (readingList != null) {
      model.addAttribute("books", readingList);
      model.addAttribute("reader", reader);
      model.addAttribute("amazonID", amazonProperties.getAssociateId);   ←---向模型中添加Associate ID
    }
    return "readingList";
  }

  @RequestMapping(method=RequestMethod.POST)
  public String addToReadingList(Reader reader, Book book) {
    book.setReader(reader);
    readingListRepository.save(book);
    return "redirect:/";
  }

}

  

ReadingListController不再直接加載配置屬性,轉而通過注入其中的AmazonProperties Bean來獲取所需的信息。

如你所見,配置屬性在調優方面十分有用,這裡說的調優不僅涵蓋了自動配置的組件,還包括注入自有應用程序Bean的細節。但如果我們想為不同的部署環境配置不同的屬性又該怎麼辦?讓我們看看如何使用Spring的Profile來設置特定環境的配置。

3.2.3 使用Profile進行配置

當應用程序需要部署到不同的運行環境時,一些配置細節通常會有所不同。比如,數據庫連接的細節在開發環境下和測試環境下就會不一樣,在生產環境下又不一樣。Spring Framework從Spring 3.1開始支持基於Profile的配置。Profile是一種條件化配置,基於運行時激活的Profile,會使用或者忽略不同的Bean或配置類。

舉例來說,假設我們在代碼清單3-1里創建的安全配置是針對生產環境的,而自動配置的安全配置用在開發環境剛剛好。在這個例子中,我們就能為SecurityConfig加上@Profile註解:

@Profile("production")
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

...

}

  

這裡用的@Profile註解要求運行時激活production Profile,這樣才能應用該配置。如果production Profile沒有激活,就會忽略該配置,而此時缺少其他用於覆蓋的安全配置,於是應用自動配置的安全配置。

設置spring.profiles.active屬性就能激活Profile,任意設置配置屬性的方式都能用於設置這個值。例如,在命令行裡運行應用程序時,可以這樣激活production Profile:

$ java -jar readinglist-0.0.1-SNAPSHOT.jar --
     spring.profiles.active=production

  

也可以向application.yml裡添加spring.profiles.active屬性:

spring:
  profiles:
    active: production

  

還可以設置環境變量,將其放入application.properties,或者使用3.2節開頭提到的各種方法。

但由於Spring Boot的自動配置替你做了太多的事情,要找到一個能放置@Profile的地方還真不怎麼方便。幸運的是,Spring Boot支持為application.properties和application.yml裡的屬性配置Profile。

為了演示區分Profile的屬性,假設你希望針對生產環境和開發環境能有不同的日誌配置。在生產環境中,你只關心WARN或更高級別的日誌項,想把日誌寫到日誌文件裡。在開發環境中,你只想把日誌輸出到控制台,記錄DEBUG或更高級別。

而你所要做的就是為每個環境分別創建配置。那要怎麼做呢?這取決於你用的是屬性文件配置還是YAML配置。

1. 使用特定於Profile的屬性文件

如果你正在使用application.properties,可以創建額外的屬性文件,遵循application-{profile}.properties這種命名格式,這樣就能提供特定於Profile的屬性了。

在日誌這個例子裡,開發環境的配置可以放在名為application-development.properties的文件裡,配置包含日誌級別和輸出到控制台:

logging.level.root=DEBUG

  

對於生產環境,application-production.properties會將日誌級別設置為WARN或更高級別,並將日誌寫入日誌文件:

logging.path=/var/logs/
logging.file=BookWorm.log
logging.level.root=WARN

  

與此同時,那些並不特定於哪個Profile或者保持默認值(以防萬一有哪個特定於Profile的配置不指定這個值)的屬性,可以繼續放在application.properties裡:

amazon.associateId=habuma-20
logging.level.root=INFO

  

2. 使用多Profile YAML文件進行配置

如果使用YAML來配置屬性,則可以遵循與配置文件相同的命名規範,即創建application{profile}.yml這樣的YAML文件,並將與Profile無關的屬性繼續放在application.yml裡。

但既然用了YAML,你就可以把所有Profile的配置屬性都放在一個application.yml文件裡。舉例來說,我們可以像下面這樣聲明日誌配置:

logging:
  level:
    root: INFO

---

spring:
  profiles: development

logging:
  level:
    root: DEBUG

---

spring:
  profiles: production

logging:
  path: /tmp/
  file: BookWorm.log
  level:
    root: WARN

  

如你所見,這個application.yml文件分為三個部分,使用一組三個連字符(---)作為分隔符。第二段和第三段分別為spring.profiles指定了一個值,這個值表示該部分配置應該應用在哪個Profile裡。第二段中定義的屬性應用於開發環境,因為spring.profiles設置為development。與之類似,最後一段的spring.profile設置為production,在production Profile被激活時生效。

另一方面,第一段並未指定spring.profiles,因此這裡的屬性對全部Profile都生效,或者對那些未設置該屬性的激活Profile生效。

除了自動配置和外置配置屬性,Spring Boot還有其他簡化常用開發任務的絕招:它自動配置了一個錯誤頁面,在應用程序遇到錯誤時顯示。3.3節,我們會介紹Spring Boot的錯誤頁,以及如何定制這個錯誤頁來適應我們的應用程序。