將 Pkl 與 Spring Boot 集成
1. 概述
在本教程中,我們將學習如何使用Pkl (發音為 Pickle)(一種配置即程式碼語言)在 Spring Boot 應用程式中定義配置。
傳統上,我們可能在 YAML、JSON 或基於鍵值的屬性檔案中定義應用程式設定。然而,這些都是靜態格式,驗證其屬性具有挑戰性。此外,隨著配置屬性數量的增加,定義更複雜的分層配置變得越來越困難。
因此,透過 Pkl、 HCL(Hashicorp 配置語言)和Dhal 配置語言等特殊語言使用配置即程式碼(CaC)可以幫助我們克服靜態屬性格式檔案的挑戰。
2. Pkl 簡介
配置即程式碼是一個流行的概念,它提倡「不要重複自己」(DRY)原則並有助於簡化配置管理。它採用聲明性編碼風格,提供了一種結構化且有效的方法來定義配置模板。它還提高了配置的可讀性。
Pkl 有助於定義各種元素,例如物件類型、集合、映射和各種原始資料類型。這種靈活性使得語言具有可擴展性,並有助於輕鬆、清晰、簡潔地建模複雜的配置。此外,它的類型和驗證機制有助於在應用程式部署之前捕獲配置錯誤。
此外,Pkl 提供了出色的工具支持,以便於採用。它具有用於生成不同語言(如 Java、Kotlin、Go 和 Swift)程式碼的工具。這對於在這些程式語言上建立的應用程式中嵌入和讀取 Pickle 配置至關重要。
此外, IntelliJ和VS Code等 IDE 具有插件,可以方便使用 Pkl 進行設定開發。 Pkl 還附帶一個名為pkl的 CLI,可協助評估 pickle 模組。它的功能之一是將.pkl配置轉換為 JSON、YAML 和 XML 格式。
3. Spring 配置 Java Bean 綁定
定義 Spring 配置最常見的方法是建立屬性檔案並使用@Value註解注入它們。然而,這通常會導致過多的樣板程式碼。
值得慶幸的是, Spring 框架借助@ConfigurationProperties註解簡化了這個過程,實現了配置與 Java bean 的無縫綁定。
然而,使用這種方法,我們仍然必須手動建立 Java bean,並對成員欄位進行必要的驗證。因此,配置漂移很難檢測,並且經常會導致應用程式中出現嚴重錯誤。因此,像 Pkl 這樣具有自動 Java 程式碼產生支援的配置定義語言是整合我們的應用程式配置的更強大的方法。
4. Spring Boot 集成
Pkl 提供從 Pickle 檔案產生 POJO 的函式庫。稍後在運行時,pkl-spring 庫可以將 Pickle 配置填入 POJO 中。讓我們了解如何將它與 Spring Boot 應用程式整合。
4.1.先決條件
首先,我們將包含pkl-spring函式庫的Maven 依賴項:
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-spring</artifactId>
<version>0.16.0</version>
</dependency>
此外,我們將使用exec-maven-plugin從 Pickle 設定檔產生 POJO:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>gen-pkl-java-bind</id>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.pkl.codegen.java.Main</mainClass>
<includeProjectDependencies>false</includeProjectDependencies>
<additionalClasspathElements>
<classpathElement>${pkl-tools-filepath}/pkl-tools-0.27.2.jar</classpathElement>
</additionalClasspathElements>
<arguments>
<argument>${project.basedir}/src/main/resources/ToolIntegrationTemplate.pkl</argument>
<argument>-o</argument>
<argument>${project.build.directory}/generated-sources</argument>
<argument>--generate-spring-boot</argument>
<argument>--generate-getters</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
Maven 外掛程式執行 Java 程式碼產生器工具pkl-tools :
java -cp pkl-tools-0.27.2.jar org.pkl.codegen.java.Main \
src/main/resources/ToolIntegration.pkl \
-o ${project.basedir}/src/main --generate-spring-boot
假設有一個Pickle檔案ToolIntegrationTemplate.pkl,工具會在target/generated-sources資料夾中產生與Pickle檔案對應的原始程式碼。
–generate-spring-boot參數將必要的 Spring Boot 類別層級@ConfigurationProperties註解包含到 Java bean 中。此外, –generate-getters參數將屬性鍵宣告為私有的。
對於 Gradle 用戶來說幸運的是, pkl-gladle 插件提供了對生成 POJO 的開箱即用支援。
4.2.在 Pkl 中建立配置
讓我們考慮一個資料整合應用程序,它從 Git 和 Jira 等來源系統獲取資料並將其發送到其他目標系統。
讓我們先定義 Pickle 範本ToolIntegrationTemplate.pkl來儲存連線屬性:
module com.baeldung.spring.pkl.ToolIntegrationProperties
class Connection {
url:String
name:String
credential:Credential
}
class Credential {
user:String
password:String
}
gitConnection: Connection
jiraConnection: Connection
總的來說,我們定義了兩個 Pkl 類別Connection和Credential ,並宣告了兩個Connection類型的物件gitConnection和jiraConnection 。
接下來我們在application.pkl檔案中定義gitConnection和jiraConnection :
amends "ToolIntegrationTemplate.pkl"
gitConnection {
url = "https://api.github.com"
name = "GitHub"
credential {
user = "gituser"
password = read("env:GITHUB_PASSWORD")
}
}
jiraConnection {
url = "https://jira.atlassian.com"
name = "Jira"
credential {
user = "jirauser"
password = read("env:JIRA_PASSWORD")
}
}
我們已用資料來源的連接屬性填入了模板。值得注意的是,我們沒有在設定檔中對密碼進行硬編碼。相反,我們使用 Pkl read()函數從環境變數中檢索密碼,最好是安全的方法。
4.3.將 Pkl 模板轉換為 POJO
在 Pickle 檔案中定義設定後,可以透過執行pom.xml檔案中定義的 Maven 目標exec:java來產生 POJO:
mvn exec:java@gen-pkl-java-bind
最終,pkl-tools庫產生一個POJO和一個屬性檔:
ToolIntegrationProperties類別由兩個內部類別組成, Connection和Credential 。 它還附帶@ConfigurationProperties註釋,這有助於將application.pkl中的屬性與ToolIntegrationProperties物件綁定。
4.4.將 Pickle 配置綁定到 POJO
我們先定義與來源系統整合的服務類別JiraService和GitHubService :
public class JiraService {
private final ToolIntegrationProperties.Connection jiraConnection;
public JiraService(ToolIntegrationProperties.Connection connection) {
this.jiraConnection = connection;
}
// ...methods getting data from Jira
}
public class GitHubService {
private final ToolIntegrationProperties.Connection gitConnection;
public GitHubService(ToolIntegrationProperties.Connection connection) {
this.gitConnection = connection;
}
// ...methods getting data from GitHub
}
這兩項服務都有以ToolIntegrationProperties作為參數的建構子。稍後,將參數中的連接詳細資訊指派給ToolIntegrationProperties.Connection.
接下來,我們將定義一個配置類,實例化服務並將其宣告為 Spring 框架 bean:
@Configuration
public class ToolConfiguration {
@Bean
public GitHubService getGitHubService(ToolIntegrationProperties toolIntegration) {
return new GitHubService(toolIntegration.getGitConnection());
}
@Bean
public JiraService getJiraService(ToolIntegrationProperties toolIntegration) {
return new JiraService(toolIntegration.getJiraConnection());
}
}
在應用程式啟動期間,Spring 框架將方法參數與application.pkl檔案中的配置綁定。最終,透過呼叫服務建構函式來實例化 bean。
4.5.服務注入和執行
最後,我們可以在其他 Spring 元件中使用@Autowired註解注入服務 Bean 。
使用@SpringBootTest ,我們將驗證應用程式是否可以從 Pickle 檔案載入 Jira 連線配置:
@SpringBootTest
public class SpringPklUnitTest {
@Autowired
private JiraService jiraService;
@Test
void whenJiraConfigsDefined_thenLoadFromApplicationPklFile() {
ToolIntegrationProperties.Connection jiraConnection = jiraService.getJiraConnection();
ToolIntegrationProperties.Credential jiraCredential = jiraConnection.getCredential();
assertAll(
() -> assertEquals("Jira", jiraConnection.getName()),
() -> assertEquals("https://jira.atlassian.com", jiraConnection.getUrl()),
() -> assertEquals("jirauser", jiraCredential.getUser()),
() -> assertEquals("jirapassword", jiraCredential.getPassword()),
() -> assertEquals("Reading issues from Jira URL https://jira.atlassian.com",
jiraService.readIssues())
);
}
}
為了演示,我們透過pom.xml檔案在環境變數中設定了 Git 和 JIRA 密碼。執行測試後,我們確認 Jira 連線和憑證詳細資訊與application.pkl檔案中定義的值相符。最後,我們也假設如果正確實現, JiraService#readIssues()將成功執行。目前,該方法僅傳回一個虛擬字串。
類似地,讓我們檢查應用程式啟動後是否從 Pickle 檔案載入 GitHub 連線配置:
@SpringBootTest
public class SpringPklUnitTest {
@Autowired
private GitHubService gitHubService;
@Test
void whenGitHubConfigsDefined_thenLoadFromApplicationPklFile() {
ToolIntegrationProperties.Connection gitHubConnection = gitHubService.getGitConnection();
ToolIntegrationProperties.Credential gitHubCredential = gitHubConnection.getCredential();
assertAll(
() -> assertEquals("GitHub", gitHubConnection.getName()),
() -> assertEquals("https://api.github.com", gitHubConnection.getUrl())
() -> assertEquals("gituser", gitHubCredential.getUser()),
() -> assertEquals("gitpassword", gitHubCredential.getPassword()),
() -> assertEquals("Reading issues from GitHub URL https://api.github.com",
gitHubService.readIssues())
);
}
}
如預期的那樣,這一次,GitHub 連接和憑證詳細資訊也與application.pkl檔案中定義的值相符。因此,有了正確的連接詳細信息,我們可以推測,如果正確實現, GitHubServiceService#readIssues()將連接到 GitHub 並獲取問題。與JiraService#readIssues()一樣,該方法目前僅傳回一個虛擬字串。
5. 結論
在本文中,我們了解了使用 Pickle 檔案定義 Spring Boot 應用程式設定的好處和方法。然而,掌握Pkl語言概念對於設計可擴展和可維護的複雜配置同樣重要。此外,了解 Spring 框架將外部屬性綁定到 POJO 的功能也是必不可少的。
與往常一樣,本文中使用的程式碼可在 GitHub 上找到。