Spring Boot通過@ConfigurationProperties訪問靜態資料 - reflectoring

banq發表於2019-11-15

使用@ConfigurationPropertiesSpring Boot,可以輕鬆地從外部源(尤其是本地配置檔案)載入配置。這些檔案可以包含自定義的複雜資料結構,因此非常適合我們不想在原始碼或資料庫中維護的靜態資料。

我們的應用程式中需要一些結構化的靜態資料。在我們構建了將資料儲存在資料庫中並允許使用者自己維護資料的完整功能之前,靜態資料也許是一種解決方法。或者,我們只需要一種方法來輕鬆維護和訪問很少更改的資料,而無需將其儲存在資料庫中的開銷。

用例可能是:

  • 維護一個包含結構資訊的大型列舉,該資訊會不時更改-我們不想在程式碼中使用列舉,因為我們不想為每個更改重新編譯整個應用程式,或者
  • 在應用程式中顯示靜態資料,例如發票抬頭中執行長的姓名和地址或網頁上的“每日報價”,或者
  • 使用任何結構化的資料,您可能會想到您不想在程式碼或資料庫中進行維護。

通過其@ConfigurationProperties功能,Spring Boot支援從一個或多個配置檔案訪問結構化資料。

在本文中,我們將看一下:

  • 如何使用資料建立配置檔案,
  • 如何建立用於驗證設定的整合測試,以及
  • 如何訪問應用程式中的資料。

我們將以“ Quote of the Day”用例為例(實際上,我是在幾周前將其構建為向我之前的團隊告別的:)。

本文隨附GitHub上的示例程式碼。

將靜態資料儲存在配置檔案中

首先,我們建立一個quotes.yml包含我們的靜態資料的YAML檔案:

static:
  quotes:
  - text: "A clever person solves a problem. A wise person avoids it."
    author: "Albert Einstein"
  - text: "Adding manpower to a late software project makes it later."
    author: "Fred Brooks"

如果您更喜歡YAML的屬性檔案,則可以使用它。使用YAML表示巢狀的資料結構更容易。

在我們的例子中,每個引用都有一個文字和一個作者。每個引用將稍後在一個Quote物件中表示。

請注意,我們為資料加上了字首static:quotes。這是建立唯一名稱空間的必要條件,因為Spring Boot稍後將合併此配置檔案的內容及其其餘配置。

讓Spring Boot意識到配置檔案

現在,我們必須使Spring Boot知道此配置檔案。我們可以通過在spring.config.location每次啟動Spring Boot應用程式時設定系統屬性來做到這一點:

-Dspring.config.location=./,./quotes.yml

這告訴Spring Boot 在當前資料夾中搜尋一個application.properties或application.yml檔案(這是預設設定),並另外載入該檔案quotes.yml。

這是Spring Boot載入YAML檔案並在應用程式中公開內容所需要做的一切。

訪問靜態資料

首先,我們需要一個Quote資料結構,用作配置資料的容器:

public class Quote {

  private String text;
  private String author;

  public Quote() {
  }

  // getters and setters omitted
}

該Quote類只有簡單的String屬性。如果我們有更復雜的資料型別,則可以使用自定義轉換器將配置引數(始終為Strings)轉換為自定義型別。

然後,我們利用Spring Boot的@ConfigurationProperties功能將靜態資料繫結到QuotesProperties物件:

@Component
@ConfigurationProperties("static")
public class QuotesProperties {

  private final List<Quote> quotes;

  public QuotesProperties(List<Quote> quotes) {
    this.quotes = quotes;
  }

  public List<Quote> getQuotes(){
    return this.quotes;
  }

}

這就是我們的名稱空間字首起作用的地方。將QuotesProperties類繫結到名稱空間static和quotes在配置檔案結合同名領域字首。

當配置屬性的繫結失敗時,Spring Boot在錯誤訊息中有點不透明。您可能會收到錯誤訊息,例如Binding to target ... failed ... property was left unbound不知道根本原因。

就我而言,根本原因始終是我沒有在充當配置屬性(在本例中為)的資料結構的類之一中提供預設建構函式以及getter和setter方法Quote。Spring Boot需要一個無引數的建構函式以及getter和setter來填充資料。

驗證對靜態資料的訪問

為了測試我們的靜態資料是否按預期工作,我們可以建立一個簡單的整合測試

@SpringBootTest(
  properties = { "spring.config.location = ./,file:./quotes.yml" }
)
class QuotesPropertiesTest {

  @Autowired
  private QuotesProperties quotesProperties;

  @Test
  void staticQuotesAreLoaded() {
    assertThat(quotesProperties.getQuotes()).hasSize(2);
  }

}

該測試最重要的部分是設定spring.config.location屬性以告訴Spring Boot拾取我們的quotes.yml檔案。

然後,我們可以簡單地注入QuotesPropertiesbean並斷言它包含我們期望的引號。

訪問靜態資料

在安裝了QuotesPropertiesbean並對其進行了測試之後,我們現在可以簡單地將其注入任何其他bean中,以執行我們需要的引號。例如,我們可以構建一個排程程式,每5秒記錄一次隨機報價:

@Configuration
@EnableScheduling
public class RandomQuotePrinter {

  private static final Logger logger = 
    LoggerFactory.getLogger(RandomQuotePrinter.class);
  private final Random random = new Random();
  private final QuotesProperties quotesProperties;

  public RandomQuotePrinter(QuotesProperties quotesProperties) {
    this.quotesProperties = quotesProperties;
  }

  @Scheduled(fixedRate = 5000)
  void printRandomQuote(){
    int index = random.nextInt(quotesProperties.getQuotes().size());
    Quote quote = quotesProperties.getQuotes().get(index);
    logger.info("'{}' - {}", quote.getText(), quote.getAuthor());
  }
}

 

相關文章