知識庫 / Spring RSS 訂閱

關於春季翻轉指南

Spring
HongKong
2
02:05 PM · Dec 06 ,2025

 

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 映射到不同配置(例如 devtestprod)的功能。 擴展此功能,將特徵標誌映射到激活的配置文件,具有直觀的意義。

讓我們看看如何根據激活的 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 來進行功能切換。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.