Spring Boot og Togglz Aspect

1. Oversikt

I denne opplæringen skal vi ta en titt på hvordan Togglz biblioteket kan brukes med en Spring Boot-applikasjon.

2. Togglz

De Togglz biblioteket gir en implementering av Feature Veksler design mønster. Dette mønsteret refererer til å ha en mekanisme som gjør det mulig å bestemme i løpet av en applikasjon om en bestemt funksjon er aktivert eller ikke basert på en bryter.

Deaktivering av en funksjon på kjøretid kan være nyttig i en rekke situasjoner, for eksempel å jobbe med en ny funksjon som ennå ikke er fullført, og ønsker å gi tilgang til en funksjon bare til en delmengde brukere eller kjøre A / B-testing.

I de følgende avsnittene vil vi lage et aspekt som avlytter metoder med en kommentar som gir et funksjonsnavn, og bestemmer om vi vil fortsette å utføre metodene, avhengig av om funksjonen er aktivert eller ikke.

3. Maven-avhengigheter

Sammen med Spring Boot avhengigheter, er Togglz biblioteket gir en 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 nyeste versjonene av togglz-spring-boot-starter, togglz-spring-security, spring-boot-starter-web, spring-boot-starter-data-jpa, spring-boot-starter-test, h2 kan lastes ned fra Maven Sentral.

4. Togglz-konfigurasjon

De togglz-spring-boot-starter biblioteket inneholder automatisk konfigurasjon for å lage de nødvendige bønner som FeatureManager. Den eneste bønnen vi trenger å tilby er featureProvider bønne.

La oss først lage en oppregning som implementerer Trekk grensesnitt og inneholder en liste over funksjonsnavn:

offentlig enum MyFeatures implementerer Feature {@Label ("Employee Management Feature") EMPLOYEE_MANAGEMENT_FEATURE; offentlig boolsk isActive () {return FeatureContext.getFeatureManager (). isActive (dette); }}

Oppregningen definerer også en metode som kalles er aktiv() som verifiserer om en bestemt funksjon er aktivert.

Da kan vi definere en bønne av typen EnumBasedFeatureProvider i en konfigurasjonsklasse Spring Boot:

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

5. Lage aspektet

Deretter vil vi lage et aspekt som avlytter en skikk AssociatedFeature kommentar og sjekker funksjonen i kommentarparameteren for å avgjøre om den er aktiv eller ikke:

@Aspect @Component offentlig klasse FeaturesAspect {privat statisk slutt Logger LOG = Logger.getLogger (FeaturesAspect.class); @Around ("@within (featureAssociation) || @annotation (featureAssociation)") offentlig Object checkAspect (ProceedingJoinPoint joinPoint, FeatureAssociation featureAssociation) kaster Throwable {if (featureAssociation.value (). IsActive ()) {return joinPoint.proceed () ; } annet {LOG.info ("Feature" + featureAssociation.value (). name () + "er ikke aktivert!"); return null; }}}

La oss også definere den tilpassede merknaden som heter FeatureAssociation som vil ha en verdi() parameter av typen MyFeatures enum:

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

Hvis funksjonen er aktiv, vil aspektet fortsette kjøringen av metoden; hvis ikke, logger den en melding uten å kjøre metoden.

6. Aktivering av funksjoner

En funksjon i Togglz kan være enten aktiv eller inaktiv. Denne oppførselen styres av en aktivert flagg og eventuelt en aktiveringsstrategi.

For å stille inn aktivert flagg til sant, kan vi bruke @EnabledByDefault merknad om definisjonen av enumverdien.

Togglz biblioteket gir også en rekke aktiveringsstrategier som kan brukes til å bestemme om en funksjon er aktivert basert på en bestemt tilstand.

I vårt eksempel, la oss bruke SystemPropertyActivationStrategy for vår EMPLOYEE_MANAGEMENT_FEATURE som evaluerer funksjonens tilstand basert på verdien til en systemegenskap. Det nødvendige eiendomsnavnet og verdien kan spesifiseres ved hjelp av @ActivationParameter kommentar:

public enum MyFeatures implementerer Feature {@Label ("Employee Management Feature") @EnabledByDefault @DefaultActivationStrategy (id = SystemPropertyActivationStrategy.ID, parameters = {@ActivationParameter (name = SystemPropertyActivationStrategy.PARAM_ProAM_PERAM_PROAM_PARAM_PARAM_PROAM_PARAM_PROAM_PARAM_PROAM_PARAM_PRO) name = SystemPropertyActivationStrategy.PARAM_PROPERTY_VALUE, value = "true")}) EMPLOYEE_MANAGEMENT_FEATURE; // ...}

Vi har angitt at funksjonen vår bare skal være aktivert hvis ansatt. funksjon eiendommen har verdien ekte.

Andre typer aktiveringsstrategier som tilbys av Togglz biblioteket er:

  • BrukernavnActivationStrategy - lar funksjonen være aktiv for en spesifisert brukerliste
  • UserRoleActivationStrategy - den nåværende brukerens rolle brukes til å bestemme tilstanden til en funksjon
  • ReleaseDateActivationStrategy - aktiverer automatisk en funksjon på en bestemt dato og et tidspunkt
  • GradualActivationStrategy - aktiverer en funksjon for en spesifisert prosentandel av brukere
  • ScriptEngineActivationStrategy - tillater bruk av et tilpasset skript skrevet på et språk som støttes av ScriptEngine av JVM for å avgjøre om en funksjon er aktiv eller ikke
  • ServerIpActivationStrategy - en funksjon er aktivert basert på serverens IP-adresser

7. Testing av aspektet

7.1. Eksempel på applikasjon

For å se vårt aspekt i aksjon, la oss lage et enkelt eksempel som inneholder en funksjon for å administrere de ansatte i en organisasjon.

Ettersom denne funksjonen vil bli utviklet, kan vi legge til metoder og klasser kommentert med vår @AssociatedFeature kommentar med verdien EMPLOYEE_MANAGEMENT_FEATURE. Dette sikrer at de bare vil være tilgjengelige hvis funksjonen er aktiv.

La oss først definere en Ansatt enhetsklasse og depot basert på vårdata:

@Entity offentlig klasse ansatt {@Id privat lang id; privat dobbeltlønn; // standard konstruktør, getters, setters}
offentlig grensesnitt EmployeeRepository utvider CrudRepository {}

La oss deretter legge til en EmployeeService med en metode for å øke en ansattes lønn. Vi vil legge til @AssociatedFeature kommentar til metoden med parameteren EMPLOYEE_MANAGEMENT_FEATURE:

@Service offentlig klasse SalaryService {@Autowired EmployeeRepository medarbeiderRepository; @FeatureAssociation (verdi = MyFeatures.EMPLOYEE_MANAGEMENT_FEATURE) offentlig tomrom økeSalary (lang id) {Ansatt ansatt = ansattRepository.findById (id) .orElse (null); ansatt.setSalary (ansatt.getSalary () + ansatt.getSalary () * 0,1); employeeRepository.save (ansatt); }} 

Metoden vil bli kalt fra en / økeSalary endepunkt som vi vil ringe for testing:

@Controller offentlig klasse SalaryController {@Autowired SalaryService salaryService; @PostMapping ("/ increaseSalary") @ResponseBody public void increaseSalary (@RequestParam long id) {lønnService.increaseSalary (id); }}

7.2. JUnit Test

La oss først legge til en test der vi kaller vår POST-kartlegging etter å ha satt inn ansatt. funksjon eiendom til falsk. I dette tilfellet skal ikke funksjonen være aktiv, og verdien av den ansattes lønn skal ikke endres:

@Test offentlig ugyldighet givenFeaturePropertyFalse_whenIncreaseSalary_thenNoIncrease () kaster unntak {Employee emp = new Employee (1, 2000); ansatteRepository.save (emp); System.setProperty ("ansatt.feature", "false"); mockMvc.perform (post ("/ increaseSalary") .param ("id", emp.getId () + "")). og Expect (status (). er (200)); emp = workerRepository.findOne (1L); assertEquals ("lønn ukorrekt", 2000, emp.getSalary (), 0,5); }

Deretter la oss legge til en test der vi utfører samtalen etter å ha satt eiendommen til ekte. I dette tilfellet bør lønnsverdien økes:

@Test offentlig ugyldighet givenFeaturePropertyTrue_whenIncreaseSalary_thenIncrease () kaster unntak {Employee emp = new Employee (1, 2000); ansatteRepository.save (emp); System.setProperty ("ansatt.feature", "sant"); mockMvc.perform (post ("/ increaseSalary") .param ("id", emp.getId () + "")). og Expect (status (). er (200)); emp = employeeRepository.findById (1L) .orElse (null); assertEquals ("lønn ukorrekt", 2200, emp.getSalary (), 0,5); }

8. Konklusjoner

I denne opplæringen har vi vist hvordan vi kan integrere Togglz bibliotek med Spring Boot ved å bruke et aspekt.

Den fulle kildekoden til eksemplet finner du på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found