1. 概要

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

2. Togglz

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

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

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

3. Mavenの依存関係

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

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</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 togglz-spring-security spring-boot-starter-web spring-bootの最新バージョン-starter-data-jpa spring-boot-starter-test h2はMavenCentralからダウンロードできます。

4. Togglz構成

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

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

public enum MyFeatures implements Feature {

    @Label("Employee Management Feature")
    EMPLOYEE_MANAGEMENT_FEATURE;

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

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

次に、SpringBoot構成クラスでタイプEnumBasedFeatureProviderのBeanを定義できます。

@Configuration
public class ToggleConfiguration {

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

5. アスペクトの作成

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

@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列挙型のvalue()パラメーターを持つFeatureAssociationというカスタムアノテーションも定義しましょう。

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

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

6. 機能のアクティブ化

Togglz の機能は、アクティブまたは非アクティブのいずれかになります。 この動作は、 enabled フラグと、オプションでアクティベーション戦略によって制御されます。

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

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

この例では、 SystemPropertyActivationStrategy をEMPLOYEE_MANAGEMENT_FEATUREに使用して、Systemプロパティの値に基づいて機能の状態を評価します。 必要なプロパティ名と値は、@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ライブラリによって提供される他のタイプのアクティベーション戦略は次のとおりです。

  • UsersnameActivationStrategy –指定されたユーザーリストに対して機能をアクティブにすることができます
  • 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 を追加して、従業員の給与を増やすメソッドを追加しましょう。 @AssociatedFeature アノテーションを、パラメーターEMPLOYEE_MANAGEMENT_FEATUREを使用してメソッドに追加します。

@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);
    }
}

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

@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と統合する方法を示しました。

この例の完全なソースコードは、GitHubにあります。