Spring Boot en Togglz Aspect

1. Overzicht

In deze tutorial gaan we kijken hoe de Togglz bibliotheek kan worden gebruikt met een Spring Boot-applicatie.

2. Togglz

De Togglz bibliotheek biedt een implementatie van de Functie schakelt ontwerp patroon. Dit patroon verwijst naar het hebben van een mechanisme waarmee tijdens de looptijd van een toepassing kan worden bepaald of een bepaalde functie is ingeschakeld of niet op basis van een schakelaar.

Het uitschakelen van een functie tijdens runtime kan handig zijn in verschillende situaties, zoals het werken aan een nieuwe functie die nog niet voltooid is, alleen toegang tot een functie aan een subset van gebruikers willen toestaan ​​of A / B-tests uitvoeren.

In de volgende secties zullen we een aspect creëren dat methoden onderschept met een annotatie die een objectnaam geeft, en bepalen of we doorgaan met het uitvoeren van de methoden, afhankelijk van of de functie is ingeschakeld of niet.

3. Maven afhankelijkheden

Samen met de Spring Boot-afhankelijkheden, de Togglz bibliotheek biedt een Spring Boot Starter-jar:

 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 

De nieuwste versies van togglz-spring-boot-starter, togglz-spring-security, spring-boot-starter-web, spring-boot-starter-data-jpa, spring-boot-starter-test, h2 kunnen worden gedownload van Maven Centraal.

4. Togglz-configuratie

De togglz-spring-boot-starter bibliotheek bevat automatische configuratie voor het maken van de benodigde bonen, zoals FeatureManager. De enige boon die we moeten leveren, is de featureProvider Boon.

Laten we eerst een opsomming maken die het Voorzien zijn van interface en bevat een lijst met functienamen:

openbare opsomming MyFeatures implementeert Functie {@Label ("Functie voor personeelsbeheer") EMPLOYEE_MANAGEMENT_FEATURE; openbare boolean isActive () {retourneer FeatureContext.getFeatureManager (). isActive (this); }}

De opsomming definieert ook een methode genaamd is actief() dat controleert of een bepaalde functie is ingeschakeld.

Dan kunnen we een soort boon definiëren EnumBasedFeatureProvider in een Spring Boot-configuratieklasse:

@Configuration openbare klasse ToggleConfiguration {@Bean openbare FeatureProvider featureProvider () {retourneer nieuwe EnumBasedFeatureProvider (MyFeatures.class); }}

5. Het aspect creëren

Vervolgens zullen we een aspect creëren dat een gewoonte onderschept Bijbehorende functie annotatie en controleert de functie in de annotatieparameter om te bepalen of deze actief is of niet:

@Aspect @Component openbare klasse FeaturesAspect {privé statische laatste Logger LOG = Logger.getLogger (FeaturesAspect.class); @Around ("@within (featureAssociation) || @annotation (featureAssociation)") public Object checkAspect (ProceedingsJoinPoint joinPoint, FeatureAssociation featureAssociation) gooit Throwable {if (featureAssociation.value (). IsActive ()) {return joinPoint.proceed () ; } else {LOG.info ("Feature" + featureAssociation.value (). name () + "is niet ingeschakeld!"); null teruggeven; }}}

Laten we ook de aangepaste annotatie definiëren die wordt aangeroepen Feature Associatie dat zal een waarde() parameter van het type MyFeatures opsomming:

@Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.METHOD, ElementType.TYPE}) openbaar @interface FeatureAssociation {MyFeatures-waarde (); }

Als de functie actief is, zal het aspect de uitvoering van de methode voortzetten; zo niet, dan zal het een bericht registreren zonder de methodecode uit te voeren.

6. Functie-activering

Een functie in Togglz kan zowel actief als inactief zijn. Dit gedrag wordt gecontroleerd door een ingeschakeld vlag en optioneel een activeringsstrategie.

Om het ingeschakeld vlag op true, kunnen we de @EnabledByDefault annotatie op de enum-waardedefinitie.

Togglz bibliotheek biedt ook een verscheidenheid aan activeringsstrategieën die kunnen worden gebruikt om te bepalen of een functie is ingeschakeld op basis van een bepaalde voorwaarde.

Laten we in ons voorbeeld de SystemPropertyActivationStrategy voor onze EMPLOYEE_MANAGEMENT_FEATURE die de status van het element evalueert op basis van de waarde van een systeemeigenschap. De vereiste eigenschapnaam en waarde kunnen worden opgegeven met de @ActivatieParameter annotatie:

openbare opsomming MyFeatures implementeert functie {@Label ("Functie voor personeelsbeheer") @EnabledByDefault @DefaultActivationStrategy (id = SystemPropertyActivationStrategy.ID, parameters = {@ActivationParameter (naam = SystemPropertyActivationStrategy.PARAM_feation "), employee @ name = SystemPropertyActivationStrategy.PARAM_PROPERTY_VALUE, value = "true")}) EMPLOYEE_MANAGEMENT_FEATURE; // ...}

We hebben onze functie zo ingesteld dat deze alleen wordt ingeschakeld als de werknemer. functie eigenschap heeft de waarde waar.

Andere soorten activeringsstrategieën die door de Togglz bibliotheek zijn:

  • Gebruikersnaam Activering Strategie - staat toe dat de functie actief is voor een gespecificeerde lijst met gebruikers
  • UserRoleActivationStrategy - de huidige gebruikersrol wordt gebruikt om de status van een functie te bepalen
  • ReleaseDateActivationStrategy - activeert automatisch een functie op een bepaalde datum en tijd
  • Geleidelijke Activering Strategie - maakt een functie mogelijk voor een bepaald percentage gebruikers
  • ScriptEngineActivationStrategy - maakt het gebruik van een aangepast script mogelijk dat is geschreven in een taal die wordt ondersteund door het ScriptEngine van de JVM om te bepalen of een functie actief is of niet
  • ServerIpActivationStrategy - een functie is ingeschakeld op basis van IP-adressen van de server

7. Testen van het aspect

7.1. Voorbeeldtoepassing

Laten we, om ons aspect in actie te zien, een eenvoudig voorbeeld maken met een functie voor het beheren van de werknemers van een organisatie.

Aangezien deze functie zal worden ontwikkeld, kunnen we methoden en klassen toevoegen die zijn geannoteerd met onze @AssociatedFeature annotatie met een waarde van EMPLOYEE_MANAGEMENT_FEATURE. Dit zorgt ervoor dat ze alleen toegankelijk zijn als de functie actief is.

Laten we eerst een Werknemer entiteitsklasse en opslagplaats op basis van Spring Data:

@Entity openbare klasse Werknemer {@Id lange privé-ID; particulier dubbel salaris; // standard constructor, getters, setters}
openbare interface EmployeeRepository breidt CrudRepository {} uit

Laten we vervolgens een Medewerker Service met een methode om het salaris van een werknemer te verhogen. We zullen de @AssociatedFeature annotatie aan de methode met een parameter van EMPLOYEE_MANAGEMENT_FEATURE:

@Service openbare klasse SalaryService {@Autowired EmployeeRepository employeeRepository; @FeatureAssociation (waarde = MyFeatures.EMPLOYEE_MANAGEMENT_FEATURE) openbare ongeldige toename salaris (lange id) {Werknemer werknemer = werknemerRepository.findById (id) .orElse (null); medewerker.setSalary (medewerker.getSalary () + medewerker.getSalary () * 0.1); employeeRepository.save (medewerker); }} 

De methode wordt aangeroepen vanuit een /Loon verhogen eindpunt dat we zullen aanroepen voor testen:

@Controller openbare klasse SalaryController {@Autowired SalaryService salarisService; @PostMapping ("/ IncreaseSalary") @ResponseBody openbare ongeldige stijgingSalaris (@RequestParam lange id) {salarisService.increaseSalary (id); }}

7.2. JUnit-test

Laten we eerst een test toevoegen waarin we onze POST-toewijzing noemen nadat we de werknemer. functie eigendom aan false. In dit geval mag de functie niet actief zijn en mag de waarde van het salaris van de werknemer niet veranderen:

@Test openbare leegte gegevenFeaturePropertyFalse_whenIncreaseSalary_thenNoIncrease () gooit uitzondering {Werknemer emp = nieuwe werknemer (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 ("salaris onjuist", 2000, emp.getSalary (), 0,5); }

Laten we vervolgens een test toevoegen waarbij we de aanroep uitvoeren nadat we de eigenschap hebben ingesteld op waar. In dit geval moet de waarde van het salaris worden verhoogd:

@Test openbare leegte gegevenFeaturePropertyTrue_whenIncreaseSalary_thenIncrease () gooit uitzondering {Werknemer emp = nieuwe werknemer (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 ("salaris onjuist", 2200, emp.getSalary (), 0,5); }

8. Conclusies

In deze tutorial hebben we laten zien hoe we kunnen integreren Togglz bibliotheek met Spring Boot door een aspect te gebruiken.

De volledige broncode van het voorbeeld is te vinden op GitHub.