Vejledning til Spring Expression Language

1. Oversigt

Spring Expression Language (SpEL) er et stærkt ekspressionssprog, der understøtter forespørgsel og manipulation af en objektgraf ved kørselstid. Det kan bruges med XML- eller annoteringsbaserede fjederkonfigurationer.

Der er flere operatører tilgængelige på sproget:

TypeOperatører
Aritmetik+, -, *, /,%, ^, div, mod
Relationel, ==,! =, =, lt, gt, eq, ne, le, ge
Logiskog, eller ikke, &&, ||,!
Betinget?:
RegexTændstikker

2. Operatører

I disse eksempler bruger vi kommentarbaseret konfiguration. Flere detaljer om XML-konfiguration kan findes i senere afsnit i denne artikel.

SpEL-udtryk begynder med # symbol og er pakket i seler: #{udtryk}. Egenskaber kan henvises til på en lignende måde, startende med en $ symbol og pakket i seler: $ {property.name}. Ejendomspladsholdere kan ikke indeholde SpEL-udtryk, men udtryk kan indeholde egenskabsreferencer:

# {$ {someProperty} + 2}

Antag i eksemplet ovenfor nogetEjendom har værdi 2, så resulterende udtryk ville være 2 + 2, som ville blive evalueret til 4.

2.1. Aritmetiske operatører

Alle grundlæggende aritmetiske operatorer understøttes.

@Value ("# {19 + 1}") // 20 privat dobbelt tilføjelse; @Value ("# {'String1' + 'string2'}") // "String1 string2" private String addString; @Value ("# {20 - 1}") // 19 privat dobbelt subtrahering; @Value ("# {10 * 2}") // 20 privat dobbelt gang; @Value ("# {36/2}") // 19 privat dobbelt opdeling; @Value ("# {36 div 2}") // 18, det samme som for / operator privat dobbelt divAlphabetic; @Value ("# {37% 10}") // 7 privat dobbelt modulo; @Value ("# {37 mod 10}") // 7, det samme som for% operator privat dobbelt moduloAlphabetic; @Value ("# {2 ^ 9}") // 512 privat dobbelt powerOf; @Value ("# {(2 + 2) * 2 + 9}") // 17 private dobbelte parenteser; 

Opdelings- og modulo-operationer har alfabetiske aliasser, div til / og mod til %. Det + operatør kan også bruges til at sammenkæde strenge.

2.2. Relationelle og logiske operatører

Alle basale relationelle og logiske operationer understøttes også.

@Value ("# {1 == 1}") // ægte privat boolsk lige; @Value ("# {1 eq 1}") // ægte 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 mindreThanAlphabetic; @Value ("# {1 1}") // falsk privat boolsk størreThan; @Value ("# {1 gt 1}") // falsk privat boolsk størreThanAlphabetic; @Value ("# {1> = 1}") // ægte privat boolsk størreThanOrEqual; @Value ("# {1 ge 1}") // ægte privat boolsk størreThanOrEqualAlphabetic; 

Alle relationsoperatører har også alfabetiske aliasser. For eksempel i XML-baserede konfigurationer kan vi ikke bruge operatorer, der indeholder vinkelparenteser (<, <=,>, >=). I stedet kan vi bruge lt (Mindre end), le (mindre end eller lig), gt (større end) eller ge (større end eller lig).

2.3. Logiske operatører

SpEL understøtter alle basale logiske operationer:

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

Som med aritmetiske og relationelle operatorer har alle logiske operatorer også alfabetiske kloner.

2.4. Betingede operatører

Betingede operatører bruges til at indsprøjte forskellige værdier afhængigt af en eller anden tilstand:

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

Den ternære operatør bruges til at udføre kompakt hvis-så-ellers betinget logik inde i udtrykket. I dette eksempel forsøger vi at kontrollere, om der var rigtigt eller ikke.

En anden almindelig anvendelse for den ternære operatør er at kontrollere, om en variabel er nul og returner derefter variabelværdien eller en standard:

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

Elvis-operatøren er en måde at forkorte den ternære operatørsyntaks til ovenstående tilfælde på Groovy-sproget. Den fås også i SpEL. Koden nedenfor svarer til koden ovenfor:

@Value ("# {someBean.someProperty?: 'Default'}") // Vil injicere den medfølgende streng, hvis someProperty er nul privat String elvis;

2.5. Brug af Regex i SpEL

Det Tændstikker operatør kan bruges til at kontrollere, om en streng matcher et givet regulært udtryk eller ej.

@Value ("# {'100' matches '\ d +'}") // sand privat boolsk validNumericStringResult; @Value ("# {'100fghdjf' matches '\ d +'}") // falsk privat boolsk ugyldigNumericStringResult; @Value ("# {'valid alfabetisk streng' matcher '[a-zA-Z \ s] +'}") // sand privat boolsk validAlphabeticStringResult; @Value ("# {'ugyldig alfabetisk streng # $ 1' matcher '[a-zA-Z \ s] +'}") // falsk privat boolsk ugyldigAlphabeticStringResult; @Value ("# {someBean.someValue matches '\ d +'}") // true hvis someValue kun indeholder cifre private boolske validNumericValue;

2.6. Adgang Liste og Kort Objekter

Ved hjælp af SpEL kan vi få adgang til indholdet af enhver Kort eller Liste i sammenhængen. Vi opretter nye bønner arbejdereHolder der gemmer information om nogle arbejdere og deres lønninger i en Liste og en Kort:

@Component ("workersHolder") offentlig klasse WorkersHolder {private List workers = new LinkedList (); privat kort lønByWorkers = ny HashMap (); offentlige 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}

Nu kan vi få adgang til værdierne for samlingerne ved hjælp af SpEL:

@Value ("# {workersHolder.salaryByWorkers ['John']}") // 35000 private Heltal johnSalary; @Value ("# {workersHolder.salaryByWorkers ['George']}") // 14000 private Heltal georgeSalary; @Value ("# {workersHolder.salaryByWorkers ['Susie']}") // 47000 privat Heltal susieSalary; @Value ("# {workersHolder.workers [0]}") // John private String firstWorker; @Value ("# {workersHolder.workers [3]}") // George private String lastWorker; @Value ("# {workersHolder.workers.size ()}") // 4 private heltal numberOfWorkers;

3. Brug i Spring Configuration

3.1. Henvisning til en bønne

I dette eksempel ser vi på, hvordan du bruger SpEL i XML-baseret konfiguration. Udtryk kan bruges til at henvise til bønner eller bønnemarker / metoder. Antag for eksempel, at vi har følgende klasser:

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

Nu opretter vi en applikationskontekst, hvor udtryk bruges til at injicere værdier:

Se på someCar bønne. Det motor og hestekraft felter af someCar bruge udtryk, der er bønnehenvisninger til motor bønne og hestekraft felt hhv.

For at gøre det samme med annoteringsbaserede konfigurationer skal du bruge @Value (“# {expression}”) kommentar.

3.2. Brug af operatører i konfiguration

Hver operatør fra den første sektion af denne artikel kan bruges i XML- og annoteringsbaserede konfigurationer. Husk dog, at i XML-baseret konfiguration kan vi ikke bruge vinkelbeslagsoperatoren “<“. I stedet skal vi bruge de alfabetiske aliasser, såsom lt (mindre end) eller le (mindre end eller lig med). For annoteringsbaserede konfigurationer er der ingen sådanne begrænsninger.

offentlig klasse SpelOperators {privat boolsk lige; 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 felter}

Nu vil vi tilføje en spelOperatorer bønne til applikationskonteksten:

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

Når vi henter den bønne fra konteksten, kan vi derefter kontrollere, at værdierne blev injiceret korrekt:

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

Her kan vi se output af toString metode til spelOperatorer bønne:

[equal = true, notEqual = false, greaterThanOrEqual = true og = true, eller = true, addString = En eller anden model fremstillet af nogle mærker] 

4. Analyse af udtryk programmatisk

Til tider vil vi måske analysere udtryk uden for konfigurationskonteksten. Heldigvis er dette muligt ved hjælp af SpelExpressionParser. Vi kan bruge alle operatorer, som vi så i tidligere eksempler, men bør bruge dem uden seler og hash-symbol. Det vil sige, hvis vi vil bruge et udtryk med + operatør, når den bruges i Spring-konfiguration, er syntaksen #{1 + 1}; når den bruges uden for konfigurationen, er syntaksen simpelthen 1 + 1.

I de følgende eksempler bruger vi Bil og Motor bønner defineret i det foregående afsnit.

4.1. Ved brug af ExpressionParser

Lad os se på et simpelt eksempel:

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

ExpressionParser er ansvarlig for at analysere udtryksstrenge. I dette eksempel vil SpEL-parser simpelthen evaluere strengen 'Enhver streng' som et udtryk. Ikke overraskende bliver resultatet 'Enhver streng'.

Som med brug af SpEL i konfiguration kan vi bruge den til at kalde metoder, få adgang til egenskaber eller ringe konstruktører.

Udtryksudtryk = expressionParser.parseExpression ("'Enhver streng'. Længde ()"); Heltalsresultat = (Heltals) expression.getValue ();

Derudover kunne vi i stedet for direkte at arbejde på bogstaveligt kalde konstruktøren:

Udtryksudtryk = expressionParser.parseExpression ("ny streng ('Enhver streng'). Længde ()");

Vi kan også få adgang til bytes ejendom af Snor klasse på samme måde, hvilket resulterer i byte [] repræsentation af strengen:

Udtryksudtryk = expressionParser.parseExpression ("'Enhver streng'.bytes"); byte [] resultat = (byte []) expression.getValue ();

Vi kan kæde metodeopkald, ligesom i normal Java-kode:

Udtryksudtryk = expressionParser.parseExpression ("'Enhver streng'.placering (\" \ ", \" \ "). Længde ()"); Heltalsresultat = (Heltals) expression.getValue ();

I dette tilfælde bliver resultatet 9, fordi vi har erstattet mellemrum med den tomme streng. Hvis vi ikke ønsker at kaste udtryksresultatet, kan vi bruge den generiske metode T getValue (klasse ønsketResultType), hvor vi kan give den ønskede type klasse, som vi ønsker at blive returneret. Noter det Evaluering Undtagelse kastes, hvis den returnerede værdi ikke kan kastes til ønsketResultType:

Heltalsresultat = expression.getValue (Integer.class);

Den mest almindelige anvendelse er at give en ekspressionsstreng, der evalueres i forhold til en bestemt objektforekomst:

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

I dette tilfælde vil resultatet være lig med værdien af model felt i bil objekt, “Model 3“. Det StandardEvaluationContext klasse angiver hvilket objekt udtrykket skal evalueres mod.

Det kan ikke ændres, når kontekstobjektet er oprettet. StandardEvaluationContext er dyrt at konstruere, og under gentagen brug opbygger den cache-tilstand, der gør det muligt at udføre efterfølgende ekspressionsevalueringer hurtigere. På grund af cache er det god praksis at genbruge det StandardEvaluationContext hvor det er muligt, hvis rodobjektet ikke ændres.

Men hvis rodobjektet ændres gentagne gange, kan vi bruge mekanismen vist i eksemplet nedenfor:

Udtryksudtryk = expressionParser.parseExpression ("model"); String result = (String) expression.getValue (car);

Her kalder vi getValue metode med et argument, der repræsenterer det objekt, som vi vil anvende et SpEL-udtryk på. Vi kan også bruge det generiske getValue metode, ligesom før:

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

4.2. Ved brug af ExpressionParser for at indstille en værdi

Bruger setValue metode til Udtryk objekt returneret ved at analysere et udtryk, kan vi indstille værdier på objekter. SpEL tager sig af typekonvertering. Som standard bruger SpEL org.springframework.core.convert.ConversionService. Vi kan oprette vores egen brugerdefinerede konverter mellem typer. ConversionService er generisk opmærksom, så det kan bruges sammen med generiske lægemidler. Lad os se på, hvordan vi kan bruge det i praksis:

Bilbil = ny bil (); car.setMake ("God producent"); car.setModel ("Model 3"); car.setYearOfProduction (2014); CarPark carPark = ny CarPark (); carPark.getCars (). tilføj (bil); StandardEvaluationContext context = ny StandardEvaluationContext (carPark); ExpressionParser expressionParser = ny SpelExpressionParser (); expressionParser.parseExpression ("biler [0] .model"). setValue (kontekst, "Anden model");

Den resulterende bilgenstand vil have modelAnden model”Som blev ændret fra“Model 3“.

4.3. Parser-konfiguration

I det følgende eksempel bruger vi følgende klasse:

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

Det er muligt at konfigurere ExpressionParser ved at kalde konstruktøren med en SpelParserConfiguration objekt. For eksempel hvis vi forsøger at tilføje bil objekt ind i biler vifte af Parkeringsplads klasse uden at konfigurere parseren, får vi en fejl som denne:

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

Vi kan ændre parserens opførsel, så den automatisk opretter elementer, hvis det angivne indeks er nul (autoGrowNullReferences, den første parameter til konstruktøren) eller til automatisk at udvide en matrix eller liste til at rumme elementer ud over dens oprindelige størrelse (autoGrowCollections, den anden parameter).

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

Den resulterende bil objektet vil være lig med bil objekt, der blev indstillet som det første element i biler vifte af parkeringsplads objekt fra det foregående eksempel.

5. Konklusion

SpEL er et stærkt, godt understøttet ekspressionssprog, der kan bruges på tværs af alle produkterne i forårsporteføljen. Det kan bruges til at konfigurere forårsprogrammer eller til at skrive parsere til at udføre mere generelle opgaver i ethvert program.

Kodeprøverne i denne artikel er tilgængelige i det linkede GitHub-arkiv.


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