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.