1. 概述
在為我們的 Spring 項目創建配置屬性時,我們可能會選擇將它們分散到多個文件中。 通常情況下,不同 Spring 配置文件會對應不同的屬性。
隨着屬性數量的增加,這些文件可能會包含大量的重複內容,並且變得難以閲讀。 清理這些文件將需要大量的人工工作。
在本簡短教程中,我們將探討一個名為 Spring Properties Cleaner 的 Maven 插件,它可以幫助整理並控制這些屬性。
2. 示例
2.1. 一些屬性文件
假設我們有兩個環境 – dev 和 prod。 在本示例中,我們尚未創建簡單的 application.properties 文件。 我們的 application-dev.properties 文件包含一組設置:
spring.datasource.url=jdbc:postgresql://${db_server}/mydatabase
spring.datasource.username=${USERNAME}
spring.datasource.password = ${PASSWORD}
redis_host=localhost
spring.redis.host=http://${redis_host}
spring.redis.port=6379
redis_host=localhost
spring.jpa.show-sql=true
upstream.host = myapp.dev.myorg.com
# upstream services
upstream.service.users.url=http://${upstream.host}/api/users
upstream.service.products.url=http://${upstream.host}/api/products
spring.redis.timeout=10000然後,我們的 application-prod.properties 文件包含一套不同的配置:
spring.datasource.url=jdbc:postgresql://${db_server}/mydatabase
spring.datasource.username=${USERNAME}
spring.datasource.password = ${PASSWORD}
# upstream services
upstream.service.users.url=https://${upstream.host}/api/users
upstream.service.products.url=https://${upstream.host}/api/products
redis_host=azure.redis6a5d54.microsoft.com
spring.redis.host=https://${redis_host}
spring.redis.port=6379
upstream.host = myapp.prod.myorg.com
spring.redis.timeout=2000在接下來的教程中,我們將整理這些文件。
2.2. 哪些問題存在於 Properties 文件中?
讓我們回顧一下上述文件中存在的問題:
- 鍵 redis_host 在 dev 配置文件中出現了兩次
- 有時,我們的鍵格式為 name=value,有時則包含額外的空格——name = value
- Properties 文件未按任何邏輯順序排序,在文件不同部分中存在多個 spring.redis 鍵
- “上游服務” URL 列表在兩種配置中基本上相同,但由於在 dev 中為 http,而在 prod 中為 https,因此無法共享
- spring.datasource 屬性在文件中似乎相同,可能是一個通用的 application.properties 的候選者
即使這些文件很短,也需要考慮很多細節,以嘗試改進它們。
讓我們使用 Spring Properties Cleaner 自動化它。 然後,讓我們使用該插件作為檢查器,以確保它不會再次進入這種狀態。
3. 將 Spring 屬性清理器添加到我們的構建中
Spring 屬性清理器作為 Maven 插件提供。 如果它檢測到屬性文件中存在任何問題,它將導致我們的構建失敗。
我們首先在我們的 pom.xml 中添加最新版本:
<plugin>
<groupId>uk.org.webcompere</groupId>
<artifactId>spring-properties-cleaner-plugin</artifactId>
<version>1.0.6</version>
<executions>
<execution>
<goals>
<goal>scan</goal>
</goals>
</execution>
</executions>
</plugin>現在,如果運行一個 Maven 編譯,插件會報告錯誤:
$ mvn compile
...
[INFO] --- spring-properties-cleaner:1.0.3:scan (default) @ spring-properties-cleaner ---
[INFO] Executing scan on /Users/ashleyfrieze/dev/tutorials/maven-modules/maven-plugins/spring-properties-cleaner/src/main/resources
[ERROR] application-dev.properties: redis_host has duplicate values L5:'localhost',L10:'localhost'
[ERROR] File 'application-dev.properties' does not meet standard - have you run fix?
[ERROR] File 'application-prod.properties' does not meet standard - have you run fix?
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE默認配置下,插件會檢測到輕微的格式錯誤和重複的鍵值。
4. 修復重複項和格式
現在,讓我們運行 fix 操作以修復這些小錯誤:
$ mvn spring-properties-cleaner:fix然後,讓我們使用我們的版本控制軟件來審查 <em >application-dev.properties</em> 的差異:
逐步處理這些文件的修復方案是個非常好的主意,並在進行更改時將其提交到我們的版本控制系統。
通過此默認配置,我們可以看到在文件開頭和稍後位置刪除了一些空格。 此外,我們還可以看到重複的屬性已被刪除。
插件已整理好這些文件後,我們的 Maven 構建將再次成功,除非我們不小心對這些文件進行了更改,從而引入了進一步的問題。
但是,我們可以配置插件以控制我們文件的一些方面。
5. 排序我們的屬性
讓我們為插件添加排序配置:
<plugin>
...
<artifactId>spring-properties-cleaner-plugin</artifactId>
...
<configuration>
<sort>clustered</sort>
</configuration>
</plugin>在這裏,我們添加了一種聚類的方式。我們本可以選擇排序,這將會以字母順序排列鍵(將數字視為數字序列)。但是,聚類會遵循文件中的鍵的原始順序,只移動與具有相同前綴的鍵的那些鍵。
讓我們看看它在重新運行fix命令時會如何改變application-prod.properties:
排序將spring鍵聚攏,並且也把upstream.host鍵提升到redis_host之上,並將後者留在文件的底部。
在審核了所有文件的差異後,我們可以將其提交到我們的源控制系統,並查看另一個改進。
6. 嵌入前綴
如果我們的目標是重構文件,以便將常見內容放在 application.properties 中,那麼我們可能需要處理一種情況,即兩個文件本質上具有相同的值,但由於佔位符不完整,導致難以找到共同模式。
讓我們重新審視我們的示例文件如何表示 URL:
- 在 dev 中:upstream.service.users.url=http://${upstream.host}/api/users
- 在 prod 中:upstream.service.users.url=https://${upstream.host}/api/users
如果 upstream.host 佔位符也可以包含方案,那麼這兩個值將相同。
這就是 inlinePrefix 配置發揮作用的地方。它採用正則表達式並修改佔位符以嵌入重複的前綴:
<configuration>
<inlinePrefix>https?://</inlinePrefix>
</configuration>此正則表達式可以識別 https 和 http 協議。如果我們需要處理其他類似的鍵,我們可以進一步自定義它。
讓我們看看它對我們的 application-prod.properties 文件有何影響:
我們可以看到 http 協議現在已成為 upstream.host 和 redis_host 鍵的一部分。 這將使我們能夠將更多共性提取到我們的 application.properties 文件中。
讓我們將此文件提交併繼續。
7. 從常用屬性中提取
為了配置插件從常用屬性中提取,我們添加 common 配置:
<configuration>
...
<common>full</common>
</configuration>7.1. 使用完整文件提取
有三種可能的提取模式:完整(full)、一致(consistent)和多重(multiple)。在完整模式下,一個屬性必須在所有屬性文件中保持相同,才能被提升到application.properties文件中。
其他模式,一致和多重,允許某些地方出現的屬性被添加到公共文件中。這可能會產生副作用,因此需要更仔細的檢查。
讓我們看看完整模式對我們的文件做了什麼。
它創建了一個新的application.properties文件:
spring.datasource.url=jdbc:postgresql://${db_server}/mydatabase
spring.datasource.username=${USERNAME}
spring.datasource.password=${PASSWORD}
spring.redis.host=${redis_host}
spring.redis.port=6379
# upstream services
upstream.service.users.url=${upstream.host}/api/users
upstream.service.products.url=${upstream.host}/api/products這包含來自其他文件的大部分內容,採用了一種通用的格式。
我們的 application-dev.properties 文件現在已經大大縮小了:
spring.redis.timeout=10000
spring.jpa.show-sql=true
redis_host=http://localhost
upstream.host=http://myapp.dev.myorg.com我們的 application-prod.properties 文件也同樣被簡化了。
唯一需要做的,是為了讓內容更清晰,就是移除鍵之間多餘的換行。
7.2. 其他常見文件模式
在我們的示例中,我們使用了<em>完整</em>模式,這是最安全的選項,因為它只會將屬性提取到通用的 <em>application.properties</em> 文件中,前提是該屬性在所有配置文件中都保持一致。
使用 <em>一致</em> 模式,我們可以提取在所有包含該屬性的文件中都保持一致,但並非在所有文件中存在的屬性。 這種做法的副作用是,將鍵推廣到通用的文件,而我們可能希望在某些配置文件中排除這些鍵。
在 <em>多重</em> 模式下,如果一個屬性出現在多個屬性文件中並且具有最常見的取值,則該屬性將被提取到通用文件中。 例如,如果 <em>spring.redis.timeout</em> 在兩個屬性文件中設置為 <em>10000</em>,而在第三個文件中設置為 <em>20000</em>,則該模式下,<em>10000</em> 的值將位於通用的 <em>application.properties</em> 文件中,而具有異常值的文件將保留其自定義值。
當開始在文件中移動不一致的屬性時,存在風險,即某些屬性可能會成為我們需要在配置文件級別進行覆蓋的通用屬性。 這些更改需要更仔細的檢查和測試。
8. 清理垂直空白
我們可以使用 <em >remove</em> 命令移除所有垂直空白,但為了在文件中使用不同的前綴來分隔代碼塊之間的空白,我們應該使用 <em >section</em> 設置。
<configuration>
...
<whitespace>section</whitespace>
</configuration>當我們運行此修復命令時,空白已清理完畢:
現在,我們的屬性文件已整理乾淨整潔。
9. 結論
在本教程中,我們探討了隨着屬性文件變大的情況下可能出現的問題。
我們安裝了 Spring Properties Cleaner Maven 插件,並利用它來監控構建過程中的問題。然後,我們增強了其配置強度,選擇對文件進行排序和簡化選項,並最終將屬性提取到一箇中心 application.properties 文件中。
通過將此插件用作代碼檢查器,我們可以整理我們的屬性文件,並防止問題再次發生。