Spring BootとTogglzのアスペクト
1. 概要
このチュートリアルでは、TogglzライブラリをSpringBootアプリケーションで使用する方法を見ていきます。
2. Togglz
Togglz libraryは、Feature Togglesデザインパターンの実装を提供します。 このパターンは、アプリケーションの実行時に、特定の機能が有効になっているかどうかをトグルに基づいて判断できるメカニズムを持つことを指します。
実行時に機能を無効にすることは、まだ完了していない新しい機能で作業する、ユーザーのサブセットのみに機能へのアクセスを許可する、A / Bテストを実行するなど、さまざまな状況で役立ちます。
次のセクションでは、機能名を提供する注釈でメソッドをインターセプトするアスペクトを作成し、機能が有効かどうかに応じてメソッドの実行を継続するかどうかを決定します。
3. Mavenの依存関係
Spring Bootの依存関係に加えて、TogglzライブラリはSpring Boot Starterjarを提供します。
org.springframework.boot
spring-boot-starter-parent
2.0.1.RELEASE
org.togglz
togglz-spring-boot-starter
2.4.1
org.togglz
togglz-spring-security
2.4.1
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-test
com.h2database
h2
1.4.194
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()というメソッドも定義します。
次に、Spring Boot構成クラスでタイプ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ライブラリは、特定の条件に基づいて機能が有効になっているかどうかを判断するために使用できるさまざまなアクティベーション戦略も提供します。
この例では、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{ }
次に、従業員の給与を増やすメソッドを使用して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);
}
}
このメソッドは、テストのために呼び出す/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ライブラリをSpringBootと統合する方法を示しました。
例の完全なソースコードはover on GitHubにあります。