Spring Expression 언어 가이드

1. 개요

Spring Expression Language (SpEL)는 런타임에 객체 그래프 쿼리 및 조작을 지원하는 강력한 표현 언어입니다. XML 또는 주석 기반 Spring 구성과 함께 사용할 수 있습니다.

해당 언어로 사용할 수있는 여러 연산자가 있습니다.

유형 연산자
산수 +,-, *, /, %, ^, div, mod
관계형 , ==,! =, =, lt, gt, eq, ne, le, ge
논리적 및, 또는, &&, ||,!
가정 어구 ? :
정규식 성냥

2. 연산자

이 예에서는 주석 기반 구성을 사용합니다. XML 구성에 대한 자세한 내용은이 기사의 뒷부분에서 확인할 수 있습니다.

SpEL 표현식은 # 기호로 시작하고 중괄호 ( # {expression})로 묶여 있습니다. 속성은 $ 기호로 시작하여 $ {property.name} 와 같이 중괄호로 둘러싸여 유사한 방식으로 참조 될 수 있습니다 . 속성 자리 표시자는 SpEL 식을 포함 할 수 없지만 식은 속성 참조를 포함 할 수 있습니다.

#{${someProperty} + 2}

위의 예에서 someProperty의 값이 2 라고 가정 하면 결과 표현식은 2 + 2가되고 4로 평가됩니다.

2.1. 산술 연산자

모든 기본 산술 연산자가 지원됩니다.

@Value("#{19 + 1}") // 20 private double add; @Value("#{'String1 ' + 'string2'}") // "String1 string2" private String addString; @Value("#{20 - 1}") // 19 private double subtract; @Value("#{10 * 2}") // 20 private double multiply; @Value("#{36 / 2}") // 19 private double divide; @Value("#{36 div 2}") // 18, the same as for / operator private double divideAlphabetic; @Value("#{37 % 10}") // 7 private double modulo; @Value("#{37 mod 10}") // 7, the same as for % operator private double moduloAlphabetic; @Value("#{2 ^ 9}") // 512 private double powerOf; @Value("#{(2 + 2) * 2 + 9}") // 17 private double brackets; 

나누기 및 모듈로 연산에는 알파벳 별칭, div/ , mod%가 있습니다. +의 운영자는 CONCATENATE 문자열로 사용할 수있다.

2.2. 관계형 및 논리 연산자

모든 기본 관계형 및 논리 연산도 지원됩니다.

@Value("#{1 == 1}") // true private boolean equal; @Value("#{1 eq 1}") // true private boolean equalAlphabetic; @Value("#{1 != 1}") // false private boolean notEqual; @Value("#{1 ne 1}") // false private boolean notEqualAlphabetic; @Value("#{1 < 1}") // false private boolean lessThan; @Value("#{1 lt 1}") // false private boolean lessThanAlphabetic; @Value("#{1  1}") // false private boolean greaterThan; @Value("#{1 gt 1}") // false private boolean greaterThanAlphabetic; @Value("#{1 >= 1}") // true private boolean greaterThanOrEqual; @Value("#{1 ge 1}") // true private boolean greaterThanOrEqualAlphabetic; 

모든 관계 연산자에는 알파벳 별명도 있습니다. 예를 들어 XML 기반 구성에서는 꺾쇠 괄호 ( < , <=, > , > = )를 포함하는 연산자를 사용할 수 없습니다 . 대신 lt (보다 작 거나 같음), le (작거나 같음), gt (보다 큼) 또는 ge (크거나 같음)를 사용할 수 있습니다.

2.3. 논리 연산자

SpEL은 모든 기본 논리 연산을 지원합니다.

@Value("#") // true private boolean orAlphabetic; @Value("#{!true}") // false private boolean not; @Value("#{not true}") // false private boolean notAlphabetic;

산술 및 관계 연산자와 마찬가지로 모든 논리 연산자에도 알파벳 복제가 있습니다.

2.4. 조건부 연산자

조건부 연산자는 일부 조건에 따라 다른 값을 삽입하는 데 사용됩니다.

@Value("#{2 > 1 ? 'a' : 'b'}") // "a" private String ternary;

삼항 연산자는 표현식 내에서 압축 if-then-else 조건 논리를 수행하는 데 사용됩니다. 이 예에서는 사실 인지 아닌지 확인하려고합니다 .

삼항 연산자의 또 다른 일반적인 용도는 일부 변수가 null 인지 확인한 다음 변수 값 또는 기본값을 반환하는 것입니다.

@Value("#{someBean.someProperty != null ? someBean.someProperty : 'default'}") private String ternary;

Elvis 연산자는 Groovy 언어에서 사용 된 위의 경우에 대한 삼항 연산자 구문을 단축하는 방법입니다. SpEL에서도 사용할 수 있습니다. 아래 코드는 위 코드와 동일합니다.

@Value("#{someBean.someProperty ?: 'default'}") // Will inject provided string if someProperty is null private String elvis;

2.5. SpEL에서 정규식 사용

경기의 연산자는 문자열이 주어진 정규 표현식과 일치하는지 여부를 확인하는 데 사용할 수 있습니다.

@Value("#{'100' matches '\\d+' }") // true private boolean validNumericStringResult; @Value("#{'100fghdjf' matches '\\d+' }") // false private boolean invalidNumericStringResult; @Value("#{'valid alphabetic string' matches '[a-zA-Z\\s]+' }") // true private boolean validAlphabeticStringResult; @Value("#{'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' }") // false private boolean invalidAlphabeticStringResult; @Value("#{someBean.someValue matches '\d+'}") // true if someValue contains only digits private boolean validNumericValue;

2.6. 목록지도 개체에 액세스

SpEL의 도움으로 컨텍스트에서 모든 지도 또는 목록 의 내용에 액세스 할 수 있습니다 . 우리는 ListMap 에 몇몇 워커와 그들의 급여에 대한 정보를 저장할 새로운 bean workersHolder 를 만들 것입니다 .

@Component("workersHolder") public class WorkersHolder { private List workers = new LinkedList(); private Map salaryByWorkers = new HashMap(); public 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 and setters }

이제 SpEL을 사용하여 컬렉션의 값에 액세스 할 수 있습니다.

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

3. Spring 구성에서 사용

3.1. 빈 참조

이 예에서는 XML 기반 구성에서 SpEL을 사용하는 방법을 살펴 보겠습니다. 식을 사용하여 빈 또는 빈 필드 / 메소드를 참조 할 수 있습니다. 예를 들어 다음과 같은 클래스가 있다고 가정합니다.

public class Engine { private int capacity; private int horsePower; private int numberOfCylinders; // Getters and setters } public class Car { private String make; private int model; private Engine engine; private int horsePower; // Getters and setters }

이제 표현식이 값을 주입하는 데 사용되는 애플리케이션 컨텍스트를 만듭니다.

someCar 빈을 보세요 . 엔진마력 의 필드 someCar를 받는 빈 참조를 사용해주십시오 표현 엔진 콩 및 마력 각각 필드.

주석 기반 구성으로 동일한 작업을 수행하려면 @Value (“# {expression}”) 주석을 사용하십시오.

3.2. 구성에서 연산자 사용

이 기사의 첫 번째 섹션에있는 각 연산자는 XML 및 주석 기반 구성에서 사용할 수 있습니다. 그러나 XML 기반 구성에서는 꺾쇠 괄호 연산자 "<"를 사용할 수 없습니다. 대신 lt (보다 작음) 또는 le (보다 작거나 같음) 와 같은 알파벳 별명을 사용해야합니다 . 주석 기반 구성의 경우 이러한 제한이 없습니다.

public class SpelOperators { private boolean equal; private boolean notEqual; private boolean greaterThanOrEqual; private boolean and; private boolean or; private String addString; // Getters and setters
 @Override public String toString() { // toString which include all fields }

이제 애플리케이션 컨텍스트에 spelOperators 빈을 추가합니다 .

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

컨텍스트에서 해당 빈을 검색하면 값이 제대로 주입되었는지 확인할 수 있습니다.

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

여기 에서 spelOperators bean 의 toString 메소드 출력을 볼 수 있습니다 .

[equal=true, notEqual=false, greaterThanOrEqual=true, and=true, or=true, addString=Some model manufactured by Some make] 

4. 프로그래밍 방식으로 식 구문 분석

At times, we may want to parse expressions outside the context of configuration. Fortunately, this is possible, using SpelExpressionParser. We can use all operators that we saw in previous examples but should use them without braces and hash symbol. That is, if we want to use an expression with the + operator when used in Spring configuration, the syntax is #{1 + 1}; when used outside of configuration, the syntax is simply 1 + 1.

In the following examples, we will use the Car and Engine beans defined in the previous section.

4.1. Using ExpressionParser

Let's look at a simple example:

ExpressionParser expressionParser = new SpelExpressionParser(); Expression expression = expressionParser.parseExpression("'Any string'"); String result = (String) expression.getValue(); 

ExpressionParser is responsible for parsing expression strings. In this example, SpEL parser will simply evaluate the string ‘Any String' as an expression. Unsurprisingly, the result will be ‘Any String'.

As with using SpEL in configuration, we can use it to call methods, access properties, or call constructors.

Expression expression = expressionParser.parseExpression("'Any string'.length()"); Integer result = (Integer) expression.getValue();

Additionally, instead of directly operating on the literal, we could call the constructor:

Expression expression = expressionParser.parseExpression("new String('Any string').length()");

We can also access the bytes property of String class, in the same way, resulting in the byte[] representation of the string:

Expression expression = expressionParser.parseExpression("'Any string'.bytes"); byte[] result = (byte[]) expression.getValue();

We can chain method calls, just as in normal Java code:

Expression expression = expressionParser.parseExpression("'Any string'.replace(\" \", \"\").length()"); Integer result = (Integer) expression.getValue();

In this case, the result will be 9, because we have replaced whitespace with the empty string. If we don't wish to cast the expression result, we can use the generic method T getValue(Class desiredResultType), in which we can provide the desired type of class that we want to be returned. Note that EvaluationException will be thrown if the returned value cannot be cast to desiredResultType:

Integer result = expression.getValue(Integer.class);

The most common usage is to provide an expression string that is evaluated against a specific object instance:

Car car = new Car(); car.setMake("Good manufacturer"); car.setModel("Model 3"); car.setYearOfProduction(2014); ExpressionParser expressionParser = new SpelExpressionParser(); Expression expression = expressionParser.parseExpression("model"); EvaluationContext context = new StandardEvaluationContext(car); String result = (String) expression.getValue(context);

In this case, the result will be equal to the value of the model field of the car object, “Model 3“. The StandardEvaluationContext class specifies which object the expression will be evaluated against.

It cannot be changed after the context object is created. StandardEvaluationContext is expensive to construct, and during repeated usage, it builds up cached state that enables subsequent expression evaluations to be performed more quickly. Because of caching it is good practice to reuse StandardEvaluationContext where it possible if the root object does not change.

However, if the root object is changed repeatedly, we can use the mechanism shown in the example below:

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

Here, we call the getValue method with an argument that represents the object to which we want to apply a SpEL expression. We can also use the generic getValue method, just as before:

Expression expression = expressionParser.parseExpression("yearOfProduction > 2005"); boolean result = expression.getValue(car, Boolean.class);

4.2. Using ExpressionParser to Set a Value

Using the setValue method on the Expression object returned by parsing an expression, we can set values on objects. SpEL will take care of type conversion. By default, SpEL uses org.springframework.core.convert.ConversionService. We can create our own custom converter between types. ConversionService is generics aware, so it can be used with generics. Let's take a look how we can use it in practice:

Car car = new Car(); car.setMake("Good manufacturer"); car.setModel("Model 3"); car.setYearOfProduction(2014); CarPark carPark = new CarPark(); carPark.getCars().add(car); StandardEvaluationContext context = new StandardEvaluationContext(carPark); ExpressionParser expressionParser = new SpelExpressionParser(); expressionParser.parseExpression("cars[0].model").setValue(context, "Other model");

The resulting car object will have modelOther model” which was changed from “Model 3“.

4.3. Parser Configuration

In the following example, we will use the following class:

public class CarPark { private List cars = new ArrayList(); // Getter and setter }

It is possible to configure ExpressionParser by calling the constructor with a SpelParserConfiguration object. For example, if we try to add car object into the cars array of CarPark class without configuring the parser, we will get an error like this:

EL1025E:(pos 4): The collection has '0' elements, index '0' is invalid

We can change the behavior of the parser, to allow it to automatically create elements if the specified index is null (autoGrowNullReferences, the first parameter to the constructor), or to automatically grow an array or list to accommodate elements beyond its initial size (autoGrowCollections, the second parameter).

SpelParserConfiguration config = new SpelParserConfiguration(true, true); StandardEvaluationContext context = new StandardEvaluationContext(carPark); ExpressionParser expressionParser = new SpelExpressionParser(config); expressionParser.parseExpression("cars[0]").setValue(context, car); Car result = carPark.getCars().get(0);

The resulting car object will be equal to the car object which was set as the first element of the cars array of carPark object from the previous example.

5. Conclusion

SpEL은 Spring 포트폴리오의 모든 제품에서 사용할 수있는 강력하고 잘 지원되는 표현 언어입니다. Spring 애플리케이션을 구성하거나 모든 애플리케이션에서보다 일반적인 작업을 수행하는 파서를 작성하는 데 사용할 수 있습니다.

이 문서의 코드 샘플은 연결된 GitHub 리포지토리에서 사용할 수 있습니다.