Spring Expression Language Guide

1. Oversikt

Spring Expression Language (SpEL) er et kraftig uttrykkespråk som støtter spørring og manipulering av en objektgraf under kjøretid. Den kan brukes med XML- eller kommentarbaserte fjærkonfigurasjoner.

Det er flere operatører tilgjengelig på språket:

TypeOperatører
Aritmetikk+, -, *, /,%, ^, div, mod
Relasjonelt, ==,! =, =, lt, gt, eq, ne, le, ge
Logiskog, eller ikke, &&, ||,!
Betinget?:
Regexfyrstikker

2. Operatører

For disse eksemplene vil vi bruke kommentarbasert konfigurasjon. Mer informasjon om XML-konfigurasjon finner du i senere deler av denne artikkelen.

SpEL-uttrykk begynner med # symbol, og er pakket i seler: #{uttrykk}. Eiendommer kan refereres til på en lignende måte, startende med en $ symbol, og pakket inn i seler: $ {property.name}. Eiendoms plassholdere kan ikke inneholde SpEL-uttrykk, men uttrykk kan inneholde referanser for eiendom:

# {$ {someProperty} + 2}

I eksemplet ovenfor antar du noeEiendom har verdi 2, så resulterende uttrykk vil være 2 + 2, som vil bli evaluert til 4.

2.1. Aritmetiske operatører

Alle grunnleggende aritmetiske operatører støttes.

@Value ("# {19 + 1}") // 20 privat dobbel add; @Value ("# {'String1' + 'string2'}") // "String1 string2" private String addString; @Value ("# {20 - 1}") // 19 privat dobbelt subtrahering; @Value ("# {10 * 2}") // 20 private doble ganger; @Value ("# {36/2}") // 19 privat dobbel divisjon; @Value ("# {36 div 2}") // 18, det samme som for / operator private double divideAlphabetic; @Value ("# {37% 10}") // 7 privat dobbel modulo; @Value ("# {37 mod 10}") // 7, det samme som for% operator private double moduloAlphabetic; @Value ("# {2 ^ 9}") // 512 privat dobbel powerOf; @Value ("# {(2 + 2) * 2 + 9}") // 17 private doble parenteser; 

Delings- og modulo-operasjoner har alfabetiske aliaser, div til / og mod til %. De + operatøren kan også brukes til å sammenkoble strenger.

2.2. Relasjonelle og logiske operatører

Alle grunnleggende relasjonelle og logiske operasjoner støttes også.

@Value ("# {1 == 1}") // ekte privat boolsk lik; @Value ("# {1 eq 1}") // ekte privat boolsk equalAlphabetic; @Value ("# {1! = 1}") // falsk privat boolsk notEqual; @Value ("# {1 ne 1}") // falsk privat boolsk notEqualAlphabetic; @Value ("# {1 <1}") // falsk privat boolsk mindreThan; @Value ("# {1 lt 1}") // falsk privat boolsk lessThanAlphabetic; @Value ("# {1 1}") // falsk privat boolsk størreThan; @Value ("# {1 gt 1}") // falsk privat boolsk størreThanAlphabetic; @Value ("# {1> = 1}") // ekte privat boolsk greaterThanOrEqual; @Value ("# {1 ge 1}") // ekte privat boolsk størreThanOrEqualAlphabetic; 

Alle relasjonsoperatører har også alfabetiske aliaser. I XML-baserte konfigurasjoner kan vi for eksempel ikke bruke operatører som inneholder vinkelparenteser (<, <=,>, >=). I stedet kan vi bruke lt (mindre enn), le (mindre enn eller lik), gt (større enn), eller ge (større enn eller lik).

2.3. Logiske operatører

SpEL støtter alle grunnleggende logiske operasjoner:

@Value ("#") // ekte privat boolsk eller alfabetisk; @Value ("# {! True}") // falsk privat boolsk ikke; @Value ("# {not true}") // falsk privat boolsk notAlphabetic;

Som med aritmetiske og relasjonelle operatører, har alle logiske operatører også alfabetiske kloner.

2.4. Betingede operatører

Betingede operatører brukes til å injisere forskjellige verdier avhengig av noen tilstand:

@Value ("# {2> 1? 'A': 'b'}") // "a" privat streng ternær;

Den ternære operatoren brukes til å utføre kompakt hvis-så-annet betinget logikk inne i uttrykket. I dette eksemplet prøver vi å sjekke om det var ekte eller ikke.

En annen vanlig bruk for den ternære operatøren er å sjekke om noen variabler er null og returner deretter variabelverdien eller en standard:

@Value ("# {someBean.someProperty! = Null? SomeBean.someProperty: 'default'}") privat streng ternær;

Elvis-operatøren er en måte å forkorte den ternære operatørsyntaxen for saken ovenfor, brukt på Groovy-språket. Den er også tilgjengelig i SpEL. Koden nedenfor tilsvarer koden ovenfor:

@Value ("# {someBean.someProperty?: 'Default'}") // Vil injisere gitt streng hvis someProperty er null privat String elvis;

2.5. Bruke Regex i SpEL

De fyrstikker operatør kan brukes til å sjekke om en streng samsvarer med et gitt regulært uttrykk.

@Value ("# {'100' matches '\ d +'}") // sann privat boolsk validNumericStringResult; @Value ("# {'100fghdjf' matches '\ d +'}") // falsk privat boolsk ugyldigNumericStringResult; @Value ("# {'valid alfabetisk streng' matches '[a-zA-Z \ s] +'}") // true private boolean validAlphabeticStringResult; @Value ("# {'ugyldig alfabetisk streng # $ 1' samsvarer med [[a-zA-Z \ s] + '}") // falsk privat boolsk ugyldigAlphabeticStringResult; @Value ("# {someBean.someValue matches '\ d +'}") // true hvis someValue inneholder bare sifre privat boolsk validNumericValue;

2.6. Åpner Liste og Kart Objekter

Ved hjelp av SpEL kan vi få tilgang til innholdet i hvilket som helst Kart eller Liste i konteksten. Vi skal lage nye bønner arbeidereHoldere som vil lagre informasjon om noen arbeidere og deres lønn i en Liste og en Kart:

@Component ("workersHolder") offentlig klasse WorkersHolder {private List workers = new LinkedList (); private Map salaryByWorkers = nye HashMap (); offentlig WorkersHolder () {workers.add ("John"); workers.add ("Susie"); workers.add ("Alex"); workers.add ("George"); salaryByWorkers.put ("John", 35000); salaryByWorkers.put ("Susie", 47000); salaryByWorkers.put ("Alex", 12000); salaryByWorkers.put ("George", 14000); } // Getters og setters}

Nå kan vi få tilgang til verdiene til samlingene ved hjelp av SpEL:

@Value ("# {workersHolder.salaryByWorkers ['John']}") // 35000 private Heltall johnSalary; @Value ("# {workersHolder.salaryByWorkers ['George']}") // 14000 private Heltall georgeSalary; @Value ("# {workersHolder.salaryByWorkers ['Susie']}") // 47000 private Integer susieSalary; @Value ("# {workersHolder.workers [0]}") // John private String førstearbeider; @Value ("# {workersHolder.workers [3]}") // George private String lastWorker; @Value ("# {workersHolder.workers.size ()}") // 4 private Integer numberOfWorkers;

3. Brukes i vårkonfigurasjon

3.1. Henviser til en bønne

I dette eksemplet ser vi på hvordan du bruker SpEL i XML-basert konfigurasjon. Uttrykk kan brukes til å referere til bønner eller bønnefelt / -metoder. Anta for eksempel at vi har følgende klasser:

offentlig klasse Motor {privat int kapasitet; privat int hestKraft; privat int numberOfCylinders; // Getters and setters} public class Car {private String make; privat int-modell; privat motor motor; privat int hestKraft; // Getters og setters}

Nå oppretter vi en applikasjonskontekst der uttrykk brukes til å injisere verdier:

Ta en titt på noenBil bønne. De motor og hestekraft felt av noenBil bruke uttrykk som er bønnehenvisninger til motor bønne og hestekraft felt henholdsvis.

For å gjøre det samme med kommentarbaserte konfigurasjoner, bruk @Value (“# {expression}”) kommentar.

3.2. Bruke operatører i konfigurasjon

Hver operatør fra den første delen av denne artikkelen kan brukes i XML- og kommentarbaserte konfigurasjoner. Husk imidlertid at i XML-basert konfigurasjon kan vi ikke bruke vinkelbrakettoperatøren “<“. I stedet bør vi bruke de alfabetiske aliasene, som f.eks lt (mindre enn) eller le (mindre enn eller lik). For merknadsbaserte konfigurasjoner er det ingen slike begrensninger.

offentlig klasse SpelOperators {privat boolsk lik; privat boolsk notEqual; privat boolsk størreThanOrEqual; privat boolsk og; privat boolsk eller; private String addString; // Getters og setters
 @Override public String toString () {// toString som inkluderer alle felt}

Nå skal vi legge til en spelOperatorer bønne til applikasjonssammenheng:

   = 6} "/> 300 eller someCar.engine.capacity> 3000}" />

Når vi henter den bønnen fra konteksten, kan vi deretter bekrefte at verdiene ble injisert riktig:

ApplicationContext context = new ClassPathXmlApplicationContext ("applicationContext.xml"); SpelOperators spelOperators = (SpelOperators) context.getBean ("spelOperators"); 

Her kan vi se utdataene fra toString Metode av spelOperatorer bønne:

[equal = true, notEqual = false, greaterThanOrEqual = true, and = true, or = true, addString = Noen modeller produsert av noen fabrikat] 

4. Analyse av uttrykk programmatisk

Noen ganger vil vi kanskje analysere uttrykk utenfor konfigurasjonssammenheng. Heldigvis er dette mulig ved hjelp av SpelExpressionParser. Vi kan bruke alle operatorer som vi så i tidligere eksempler, men bør bruke dem uten seler og hash-symbol. Det vil si hvis vi vil bruke et uttrykk med + når den brukes i vårkonfigurasjon, er syntaksen #{1 + 1}; når den brukes utenfor konfigurasjonen, er syntaksen ganske enkelt 1 + 1.

I de følgende eksemplene vil vi bruke Bil og Motor bønner definert i forrige avsnitt.

4.1. Ved hjelp av ExpressionParser

La oss se på et enkelt eksempel:

ExpressionParser expressionParser = ny SpelExpressionParser (); Uttrykk uttrykk = expressionParser.parseExpression ("'Enhver streng'"); String result = (String) expression.getValue (); 

ExpressionParser er ansvarlig for å analysere uttrykkstrenger. I dette eksemplet vil SpEL-parser ganske enkelt evaluere strengen ‘Enhver streng’ som et uttrykk. Ikke overraskende blir resultatet ‘Enhver streng’.

Som med bruk av SpEL i konfigurasjon, kan vi bruke den til å ringe metoder, få tilgang til egenskaper eller ringe konstruktører.

Uttrykk uttrykk = expressionParser.parseExpression ("'Enhver streng'.lengde ()"); Heltallresultat = (Heltall) expression.getValue ();

I tillegg til, i stedet for å operere direkte på bokstavelig, kan vi ringe konstruktøren:

Uttrykk uttrykk = expressionParser.parseExpression ("ny streng ('Enhver streng'). Lengde ()");

Vi kan også få tilgang til byte tilhører String klasse, på samme måte, noe som resulterer i byte [] -representasjonen av strengen:

Uttrykk uttrykk = expressionParser.parseExpression ("'Enhver streng'. Bytes"); byte [] resultat = (byte []) expression.getValue ();

Vi kan kjede metodeanrop, akkurat som i vanlig Java-kode:

Uttrykk uttrykk = expressionParser.parseExpression ("'Enhver streng'. Erstatt (\" \ ", \" \ "). Lengde ()"); Heltallresultat = (Heltall) expression.getValue ();

I dette tilfellet blir resultatet 9, fordi vi har erstattet mellomrom med tom streng. Hvis vi ikke ønsker å kaste uttrykksresultatet, kan vi bruke den generiske metoden T getValue (klasse ønsketResultType), der vi kan gi ønsket type klasse som vi ønsker å bli returnert. Noter det Evaluering Unntak kastes hvis den returnerte verdien ikke kan kastes til ønsketResultType:

Heltalsresultat = expression.getValue (Integer.class);

Den vanligste bruken er å gi en uttrykkstreng som evalueres mot en spesifikk objektforekomst:

Bilbil = ny bil (); car.setMake ("God produsent"); car.setModel ("Model 3"); car.setYearOfProduction (2014); ExpressionParser expressionParser = ny SpelExpressionParser (); Uttrykk uttrykk = expressionParser.parseExpression ("modell"); EvaluationContext context = ny StandardEvaluationContext (bil); String result = (String) expression.getValue (context);

I dette tilfellet vil resultatet være lik verdien av modell felt av bil objekt, “Modell 3“. De StandardEvaluationContext class spesifiserer hvilket objekt uttrykket skal evalueres mot.

Det kan ikke endres etter at kontekstobjektet er opprettet. StandardEvaluationContext er kostbart å konstruere, og under gjentatt bruk bygger den opp hurtigbufret tilstand som gjør det mulig å utføre etterfølgende uttrykksevalueringer raskere. På grunn av hurtigbufring er det god praksis å bruke den på nytt StandardEvaluationContext der det er mulig hvis rotobjektet ikke endres.

Men hvis rotobjektet endres gjentatte ganger, kan vi bruke mekanismen vist i eksemplet nedenfor:

Uttrykkuttrykk = expressionParser.parseExpression ("modell"); String result = (String) expression.getValue (car);

Her kaller vi getValue metode med et argument som representerer objektet som vi vil bruke et SpEL-uttrykk på. Vi kan også bruke det generiske getValue metode, akkurat som før:

Ekspresjonsuttrykk = expressionParser.parseExpression ("yearOfProduction> 2005"); boolsk resultat = expression.getValue (bil, boolsk.klasse);

4.2. Ved hjelp av ExpressionParser for å sette en verdi

Bruker setValue metoden på Uttrykk objekt returnert ved å analysere et uttrykk, kan vi sette verdier på objekter. SpEL tar seg av typekonvertering. Som standard bruker SpEL org.springframework.core.convert.ConversionService. Vi kan lage vår egen tilpassede omformer mellom typer. ConversionService er generisk klar, så den kan brukes med generiske legemidler. La oss se på hvordan vi kan bruke det i praksis:

Bilbil = ny bil (); car.setMake ("God produsent"); car.setModel ("Model 3"); car.setYearOfProduction (2014); CarPark carPark = ny CarPark (); carPark.getCars (). legg til (bil); StandardEvaluationContext context = new StandardEvaluationContext (carPark); ExpressionParser expressionParser = ny SpelExpressionParser (); expressionParser.parseExpression ("biler [0] .modell"). setValue (kontekst, "Annen modell");

Det resulterende bilobjektet vil ha modellAnnen modell”Som ble endret fra“Modell 3“.

4.3. Parser-konfigurasjon

I det følgende eksemplet vil vi bruke følgende klasse:

offentlig klasse CarPark {private List biler = ny ArrayList (); // Getter og setter}

Det er mulig å konfigurere ExpressionParser ved å ringe konstruktøren med en SpelParserConfiguration gjenstand. For eksempel hvis vi prøver å legge til bil objekt inn i biler et utvalg av Bilparkering klasse uten å konfigurere parseren, får vi en feil som dette:

EL1025E: (pos 4): Samlingen har '0' -elementer, indeks '0' er ugyldig

Vi kan endre oppføringen til parseren, slik at den automatisk kan lage elementer hvis den spesifiserte indeksen er null (autoGrowNullReferanser, den første parameteren til konstruktøren), eller for automatisk å utvide en matrise eller liste for å imøtekomme elementer utover den opprinnelige størrelsen (autoGrowCollections, den andre parameteren).

SpelParserConfiguration config = ny SpelParserConfiguration (true, true); StandardEvaluationContext context = new StandardEvaluationContext (carPark); ExpressionParser expressionParser = ny SpelExpressionParser (config); expressionParser.parseExpression ("biler [0]"). setValue (kontekst, bil); Bilresultat = carPark.getCars (). Get (0);

Resultatet bil objektet vil være lik bil objekt som ble satt som det første elementet i biler et utvalg av bilparkering objekt fra forrige eksempel.

5. Konklusjon

SpEL er et kraftig, godt støttet ekspresjonsspråk som kan brukes på tvers av alle produktene i vårporteføljen. Den kan brukes til å konfigurere vårapplikasjoner eller til å skrive parsere for å utføre mer generelle oppgaver i alle applikasjoner.

Kodeprøvene i denne artikkelen er tilgjengelige i det koblede GitHub-depotet.


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