Spring BootとTogglzのアスペクト

1概要

このチュートリアルでは、 Togglz ライブラリをSpring Bootアプリケーションで使用する方法を見ていきます。

2トグルズ

Togglz library は、 Feature Toggles デザインパターンの実装を提供します。このパターンは、トグルに基づいて特定の機能が有効になっているかどうかをアプリケーションの実行時に判断できるメカニズムを持つことを意味します。

実行時に機能を無効にすることは、まだ完成していない新機能に取り組む、一部のユーザーにのみ機能へのアクセスを許可する、またはA/Bテストを実行するなど、さまざまな状況で役立ちます。

次のセクションでは、機能名を提供するアノテーションでメソッドをインターセプトするアスペクトを作成し、機能が有効になっているかどうかに応じてメソッドを実行し続けるかどうかを決定します。

3 Mavenの依存関係

Spring Bootの依存関係に加えて、 Togglz ライブラリはSpring Boot Starter jarを提供します。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>

<dependency>
    <groupId>org.togglz</groupId>
    <artifactId>togglz-spring-boot-starter</artifactId>
    <version>2.4.1</version>
<dependency>
    <groupId>org.togglz</groupId>
    <artifactId>togglz-spring-security</artifactId>
    <version>2.4.1</version>
</dependency>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.194</version>
</dependency>

togglz-spring-boot-starter 、https://search.maven.org/の最新バージョンclassic/#search%7Cga%7C1%7Ctogglz%20spring%20セキュリティ[togglz-spring-security]、https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22spring-boot-starter -web%22[spring-boot-starter-web]、https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22spring-boot-starter-data-jpa%22[spring -boot-starter-data-jpa]、https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22spring-boot-starter-test%22[spring-boot-starter-test]、https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22h2%22[h2]はMaven Centralからダウンロードできます。

4トグルズの設定

togglz-spring-boot-starter ライブラリには、 FeatureManager などの必要なBeanを作成するための自動設定が含まれています。提供する必要がある唯一のBeanは featureProvider Beanです。

まず、 Feature インターフェースを実装し、機能名のリストを含む列挙を作成しましょう。

public enum MyFeatures implements Feature {

    @Label("Employee Management Feature")
    EMPLOYEE__MANAGEMENT__FEATURE;

    public boolean isActive() {
        return FeatureContext.getFeatureManager().isActive(this);
    }
}

列挙体は、特定の機能が有効になっているかどうかを検証する isActive() というメソッドも定義します。

それからSpring Boot設定クラスで EnumBasedFeatureProvider 型のbeanを定義できます。

@Configuration
public class ToggleConfiguration {

    @Bean
    public FeatureProvider featureProvider() {
        return new EnumBasedFeatureProvider(MyFeatures.class);
    }
}

5アスペクトの作成

次に、カスタムの AssociatedFeature アノテーションをインターセプトし、annotationパラメーターで提供されている機能をチェックしてアクティブかどうかを判断するアスペクトを作成します。

@Aspect
@Component
public class FeaturesAspect {

    private static final Logger LOG = Logger.getLogger(FeaturesAspect.class);

    @Around(
      "@within(featureAssociation) || @annotation(featureAssociation)"
    )
    public Object checkAspect(ProceedingJoinPoint joinPoint,
      FeatureAssociation featureAssociation) throws Throwable {

        if (featureAssociation.value().isActive()) {
            return joinPoint.proceed();
        } else {
            LOG.info(
              "Feature " + featureAssociation.value().name() + " is not enabled!");
            return null;
        }
    }
}

タイプ MyFeatures enumの value() パラメーターを持つ FeatureAssociation という名前のカスタムアノテーションも定義しましょう。

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface FeatureAssociation {
    MyFeatures value();
}

機能がアクティブな場合、アスペクトはメソッドの実行を続けます。そうでなければ、メソッドコードを実行せずにメッセージを記録します。

6. 機能のアクティベーション

Togglz の機能はアクティブにも非アクティブにもできます。この動作は enabled フラグとオプションで有効化戦略によって制御されます。

enabled フラグをtrueに設定するには、列挙値定義に @ EnabledByDefault アノテーションを使用できます。

また、 Togglz ライブラリは、特定の条件に基づいて機能が有効になっているかどうかを判断するために使用できるさまざまなアクティブ化戦略を提供します。

この例では、Systemプロパティの値に基づいて機能の状態を評価するEMPLOYEE MANAGEMENT FEATUREに SystemPropertyActivationStrategy を使用します。必要なプロパティ名と値は、 @ ActivationParameter アノテーションを使用して指定できます。

public enum MyFeatures implements Feature {

    @Label("Employee Management Feature")
    @EnabledByDefault
    @DefaultActivationStrategy(id = SystemPropertyActivationStrategy.ID,
      parameters = {
      @ActivationParameter(
        name = SystemPropertyActivationStrategy.PARAM__PROPERTY__NAME,
        value = "employee.feature"),
      @ActivationParameter(
        name = SystemPropertyActivationStrategy.PARAM__PROPERTY__VALUE,
        value = "true") })
    EMPLOYEE__MANAGEMENT__FEATURE;
   //...
}

employee.feature プロパティの値が true の場合にのみ、機能を有効にするように設定しました。

Togglz ライブラリーによって提供される他のタイプの活動化戦略は、以下のとおりです。

  • UsernameActivationStrategy - この機能を有効にします。

指定されたユーザーのリスト ** UserRoleActivationStrategy - 現在のユーザの役割は

機能の状態を判断する ** ReleaseDateActivationStrategy - で自動的に機能を有効にする

特定の日時 ** GradualActivationStrategy - 特定の機能を有効にします。

ユーザーの割合 ** ScriptEngineActivationStrategy - カスタムスクリプトの使用を許可

JVMの ScriptEngine でサポートされている言語で書かれている 機能がアクティブかどうかを判断する ** ServerIpActivationStrategy - IPに基づいて機能が有効になります。

サーバーのアドレス

7. アスペクトのテスト

7.1. アプリケーション例

私たちの側面を実際に見るために、組織の従業員を管理するための機能を含む簡単な例を作成しましょう。

この機能が開発されるにつれて、EMPLOYEE MANAGEMENT FEATUREの値で @ AssociatedFeature アノテーションが付けられたメソッドとクラスを追加できます。これにより、機能がアクティブな場合にのみアクセス可能になります。

まず、Spring Dataに基づいて Employee エンティティクラスとリポジトリを定義しましょう。

@Entity
public class Employee {

    @Id
    private long id;
    private double salary;

   //standard constructor, getters, setters
}
public interface EmployeeRepository
  extends CrudRepository<Employee, Long>{ }

次に、従業員の給料を上げるためのメソッドを含む EmployeeService を追加しましょう。 EMPLOYEE MANAGEMENT FEATURE というパラメータを使用して、メソッドに @ AssociatedFeature アノテーションを追加します。

@Service
public class SalaryService {

    @Autowired
    EmployeeRepository employeeRepository;

    @FeatureAssociation(value = MyFeatures.EMPLOYEE__MANAGEMENT__FEATURE)
    public void increaseSalary(long id) {
        Employee employee = employeeRepository.findById(id).orElse(null);
        employee.setSalary(employee.getSalary() +
          employee.getSalary() **  0.1);
        employeeRepository.save(employee);
    }
}

このメソッドは、テストのために呼び出す /reduceSalary エンドポイントから呼び出されます。

@Controller
public class SalaryController {

    @Autowired
    SalaryService salaryService;

    @PostMapping("/increaseSalary")
    @ResponseBody
    public void increaseSalary(@RequestParam long id) {
        salaryService.increaseSalary(id);
    }
}

7.2. JUnitテスト

まず、 employee.feature プロパティを false に設定した後にPOSTマッピングを呼び出すテストを追加しましょう。この場合、この機能はアクティブにしないでください。また、従業員の給与の値は変更しないでください。

@Test
public void givenFeaturePropertyFalse__whenIncreaseSalary__thenNoIncrease()
  throws Exception {
    Employee emp = new Employee(1, 2000);
    employeeRepository.save(emp);

    System.setProperty("employee.feature", "false");

    mockMvc.perform(post("/increaseSalary")
      .param("id", emp.getId() + ""))
      .andExpect(status().is(200));

    emp = employeeRepository.findOne(1L);
    assertEquals("salary incorrect", 2000, emp.getSalary(), 0.5);
}

次に、プロパティを true に設定した後に呼び出しを実行するテストを追加しましょう。この場合、給与の値を増やす必要があります。

@Test
public void givenFeaturePropertyTrue__whenIncreaseSalary__thenIncrease()
  throws Exception {
    Employee emp = new Employee(1, 2000);
    employeeRepository.save(emp);
    System.setProperty("employee.feature", "true");

    mockMvc.perform(post("/increaseSalary")
      .param("id", emp.getId() + ""))
      .andExpect(status().is(200));

    emp = employeeRepository.findById(1L).orElse(null);
    assertEquals("salary incorrect", 2200, emp.getSalary(), 0.5);
}

8結論

このチュートリアルでは、アスペクトを使用して Togglz ライブラリをSpring Bootと統合する方法を示しました。

例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/spring-boot[over on GitHub]にあります。