1. 概述
在本教程中,我們將瞭解 Flips,這是一個通過強大的註解為 Spring Core、Spring MVC 和 Spring Boot 應用程序實現特徵標誌的庫。
特徵標誌(或開關)是一種快速、安全地交付新功能的設計模式。這些開關允許我們修改應用程序行為 而無需更改或部署新代碼。Martin Fowler 的博客上有一篇關於特徵標誌的非常有信息的內容 在此。
2. Maven 依賴
在開始之前,我們需要將 Flips 庫添加到我們的 <em pom.xml</em> 中:
<dependency>
<groupId>com.github.feature-flip</groupId>
<artifactId>flips-core</artifactId>
<version>1.0.1</version>
</dependency>Maven Central 上有該庫的最新版本 , 並且 Github 項目在 這裏。 當然,我們還需要包含 Spring:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>由於 Flips 目前與 Spring 5.x 不兼容,我們將使用 Spring Boot 4.x 分支的最新版本。
3. 一個簡單的 REST 服務用於翻轉 (Flips)
讓我們創建一個簡單的 Spring Boot 項目,用於添加和切換新的功能和標誌。
我們的 REST 應用程序將提供對 Foo 資源的訪問:
public class Foo {
private String name;
private int id;
}
我們將會創建一個Service,該Service維護一個Foos的列表:
@Service
public class FlipService {
private List<Foo> foos;
public List<Foo> getAllFoos() {
return foos;
}
public Foo getNewFoo() {
return new Foo("New Foo!", 99);
}
}
我們將會在後續內容中提及其他服務方法,但這個片段就足以説明 FlipService 在系統中的作用。
當然,我們還需要創建一個 Controller:
@RestController
public class FlipController {
private FlipService flipService;
// constructors
@GetMapping("/foos")
public List<Foo> getAllFoos() {
return flipService.getAllFoos();
}
}
4. 基於配置的控制功能
Flips 最基本的使用方式是根據配置啓用或禁用功能。Flips 提供了多個註解來實現此功能。
4.1. 環境屬性
假設我們為 FlipService 添加了一個新功能:通過 ID 檢索 Foos。
請將新請求添加到控制器中:
@GetMapping("/foos/{id}")
@FlipOnEnvironmentProperty(
property = "feature.foo.by.id",
expectedValue = "Y")
public Foo getFooById(@PathVariable int id) {
return flipService.getFooById(id)
.orElse(new Foo("Not Found", -1));
}
@FlipOnEnvironmentProperty 控制該 API 是否可用。
簡單來説,當 feature.foo.by.id 設置為 Y 時,我們可以通過 ID 進行請求。如果它未定義或未定義,Flips 將禁用 API 方法。
如果一個功能未啓用,Flips 將拋出 FeatureNotEnabledException 異常,Spring 將返回 “Not Implemented” 給 REST 客户端。
當我們將屬性設置為 N 時,我們看到的結果如下:
Status = 501
Headers = {Content-Type=[application/json;charset=UTF-8]}
Content type = application/json;charset=UTF-8
Body = {
"errorMessage": "Feature not enabled, identified by method
public com.baeldung.flips.model.Foo
com.baeldung.flips.controller.FlipController.getFooById(int)",
"className":"com.baeldung.flips.controller.FlipController",
"featureName":"getFooById"
}正如預期的那樣,Spring 會捕獲 FeatureNotEnabledException 並將狀態碼 501 返回給客户端。
4.2. 激活配置文件
Spring 長期以來就提供了將 Bean 映射到不同配置(例如 dev、test 或 prod)的功能。 擴展此功能,將特徵標誌映射到激活的配置文件,具有直觀的意義。
讓我們看看如何根據激活的 Spring 配置文件啓用或禁用功能:
@RequestMapping(value = "/foos", method = RequestMethod.GET)
@FlipOnProfiles(activeProfiles = "dev")
public List getAllFoos() {
return flipService.getAllFoos();
}
@FlipOnProfiles 註解接受一個 profile 名稱列表。如果當前 active profile 存在於列表中,則 API 將可訪問。
4.3. Spring 表達式
Spring 表達式語言 (SpEL) 是一種強大的機制,用於操縱運行時環境。Flips 允許我們使用它來啓用和禁用功能。
@FlipOnSpringExpression 裝飾器根據返回布爾值的 SpEL 表達式來啓用或禁用一個方法。
讓我們使用一個簡單的表達式來控制一個新功能:
@FlipOnSpringExpression(expression = "(2 + 2) == 4")
@GetMapping("/foo/new")
public Foo getNewFoo() {
return flipService.getNewFoo();
}
4.4. 禁用
要完全禁用某個功能,請使用 <em @FlipOff@</em>。
@GetMapping("/foo/first")
@FlipOff
public Foo getFirstFoo() {
return flipService.getLastFoo();
}
在此示例中,getFirstFoo() 完全不可訪問。
如我們將在下面看到,我們可以組合使用 Flip 註解,從而可以使用 @FlipOff 來根據環境或其他條件禁用功能。
5. 使用日期/時間控制功能
通過日期/時間或星期幾,可以切換功能的啓用/禁用狀態。將新功能的可用性與日期或星期幾綁定,具有明顯的優勢。
5.1. 日期和時間
@FlipOnDateTime 接受一個按照 ISO 8601 格式命名的屬性名稱。
例如,設置一個屬性,表示新功能將於 3 月 1 日生效:
first.active.after=2018-03-01T00:00:00Z然後我們將編寫一個用於檢索第一個 Foo 的 API:
@GetMapping("/foo/first")
@FlipOnDateTime(cutoffDateTimeProperty = "first.active.after")
public Foo getFirstFoo() {
return flipService.getLastFoo();
}
翻轉操作會檢查指定的屬性。如果該屬性存在且指定的時間/日期已過,則該功能將被啓用。
5.2. 星期幾
該庫提供 <em @FlipOnDaysOfWeek,這對於諸如 A/B 測試之類的操作非常有用:
@GetMapping("/foo/{id}")
@FlipOnDaysOfWeek(daysOfWeek={DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY})
public Foo getFooByNewId(@PathVariable int id) {
return flipService.getFooById(id).orElse(new Foo("Not Found", -1));
}
getFooByNewId() 僅在週一和週三可用。
6. 替換 Bean
切換方法的啓用和禁用非常有用,但我們可能希望通過新的對象引入新的行為。<em @FlipBean</em> 指示 Flips 調用新的 Bean 中的方法。
一個 <em @FlipBean</em> 標註可以應用於任何 Spring <em @Component</em>。 迄今為止,我們只修改了我們的 <em @RestController</em>,現在我們嘗試修改我們的 <em Service</em>。
我們將創建一個具有不同行為的服務,該服務與 <em FlipService</em> 不同:
@Service
public class NewFlipService {
public Foo getNewFoo() {
return new Foo("Shiny New Foo!", 100);
}
}
我們將會替換舊服務的 getNewFoo() 方法為新版本:
@FlipBean(with = NewFlipService.class)
public Foo getNewFoo() {
return new Foo("New Foo!", 99);
}
翻轉操作會將調用定向到 getNewThing(),NewFlipService. @FlipBean 也是一個最有用且通常與其它操作組合使用的開關。我們現在來查看它。
7. 組合開關
通過指定多個開關來組合開關。Flips 會以序列化的方式評估這些開關,並採用隱式的“與”邏輯。因此,所有開關必須為真才能啓用該功能。
以下是如何組合我們之前的一些示例:
@FlipBean(
with = NewFlipService.class)
@FlipOnEnvironmentProperty(
property = "feature.foo.by.id",
expectedValue = "Y")
public Foo getNewFoo() {
return new Foo("New Foo!", 99);
}
我們已經使用了新的服務並使其可配置。
8. 結論
在本簡要指南中,我們創建了一個簡單的 Spring Boot 服務,並使用 Flips 註解啓/禁用 API。我們觀察到功能是如何通過配置信息和日期/時間進行啓/禁用,以及如何通過運行時交換 Bean 來進行功能切換。