๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

[Spring] SpEL - Spring Expression Language

by Leica 2020. 3. 7.
๋ฐ˜์‘ํ˜•

[Spring] SpEL - Spring Expression Language

SpEL(Spring Expression Language)๋ž€?

Spring expression language๋Š” ๋ณดํ†ต SpEL๋กœ ํ‘œ๊ธฐํ•˜๋ฉฐ ๊ตฌ๋‘๋กœ๋Š” ์Šคํ”„๋ง EL์ด๋ผ๊ณ  ์ง€์นญํ•œ๋‹ค.

SpEL์€ ๋ณดํ†ต ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์—ฌ Unified EL๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ, ๋ฌธ์ž์—ด ํ…œํ”Œ๋ฆฟ ๊ธฐ๋Šฅ ๋“ฑ์˜ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ํ‘œํ˜„์‹ ์–ธ์–ด์ด๋‹ค.

OGNL, MVEL, JBoss EL ๋“ฑ ์ž๋ฐ”์—์„œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์—ฌ๋Ÿฌ EL์ด ์žˆ์ง€๋งŒ SpEL์€ Spring ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์— ๊ฑธ์ณ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ์œผ๋ฉฐ ์Šคํ”„๋ง 3.0๋ถ€ํ„ฐ ์ง€์›๋œ๋‹ค.

 

SpEL ํ‘œ๊ธฐ๋ฒ•

#{ SpELํ‘œํ˜„์‹ }

JSP์—์„œ EL์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊บผ๋‚ผ๋•Œ ${ } ์ด๋ผ๊ณ  ํ‘œ๊ธฐํ•˜๋“ฏ SpEL์€ #{ }๋กœ ํ‘œ๊ธฐํ•œ๋‹ค.

#{ } ์•ˆ์˜ ๋‚ด์šฉ์„ SpEL ํ‘œํ˜„์‹์œผ๋กœ ์ธ์‹ํ•ด์„œ ํ‘œํ˜„์‹์„ evaluation(ํ‰๊ฐ€, ์‹คํ–‰) ํ•œ๋‹ค.

์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง์—์„œ ${ } ํ‘œ๊ธฐ๋„ ์‚ฌ์šฉ๋˜๋Š”๋ฐ ์ด๋Š” SpEL์ด ์•„๋‹ˆ๋ผ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐธ์กฐํ• ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

SpEL์€ ๊ธฐ๋ณธ์ ์œผ๋กœ #{ } ๋กœ ํ‘œ๊ธฐํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•ด๋‘์ž.

 

SpEL ์ง€์› ๊ธฐ๋Šฅ

  • ๋ฆฌํ„ฐ๋Ÿด ํ‘œํ˜„์‹ (Literal Expression)
  • Boolean๊ณผ ๊ด€๊ณ„์—ฐ์‚ฐ์ž (Boolean and Relational Operator)
  • ์ •๊ทœ ํ‘œํ˜„์‹ (Regular Expression)
  • ํด๋ž˜์Šค ํ‘œํ˜„์‹ (Class Expression)
  • ํ”„๋กœํผํ‹ฐ, ๋ฐฐ์—ด, ๋ฆฌ์ŠคํŠธ, ๋งต์— ๋Œ€ํ•œ ์ ‘๊ทผ ์ง€์› (Accessing properties, arrays, lists, maps)
  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ (Method Invocation)
  • ๊ด€๊ณ„์—ฐ์‚ฐ์ž (Relational Operator)
  • ํ• ๋‹น (Assignment)
  • ์ƒ์„ฑ์ž ํ˜ธ์ถœ (Calling Constructors)
  • Bean ์ฐธ์กฐ (Bean References)
  • ๋ฐฐ์—ด ์ƒ์„ฑ (Array Contruction)
  • ์ธ๋ผ์ธ ๋ฆฌ์ŠคํŠธ/๋งต (Inline List/Map)
  • ์‚ผํ•ญ ์—ฐ์‚ฐ์ž (Ternary Operator)
  • ๋ณ€์ˆ˜ (Variables)
  • ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜ (User defined functions)
  • Collections Projection
  • Collections Selection
  • Templated expression

 

@Value ์• ๋…ธํ…Œ์ด์…˜์—์„œ SpEL ์‚ฌ์šฉ

SpEL์ด ์‹ค์งˆ์ ์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๊ณณ ์ค‘ ํ•˜๋‚˜๋Š” @Value ์• ๋…ธํ…Œ์ด์…˜์ด๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Value("#{1+1}")
int value;
 
@Value("#{'hello ' + 'world'}")
String greeting;
 
@Value("#{1 eq 5}")
boolean trueOrFalse;
 
@Value("Literal String")
String literalString;
 
@Override
public void run(ApplicationArguments args) throws Exception {
    System.out.println(value);
    System.out.println(greeting);
    System.out.println(trueOrFalse);
    System.out.println(literalString);
}
cs

 

์‹คํ–‰ ๊ฒฐ๊ณผ

 

๋นˆ์ด ๋งŒ๋“ค์–ด์งˆ๋•Œ @Value() ์•ˆ์˜ ๊ฐ’์ด #{ } ํ‘œ๊ธฐ๋กœ ๊ฐ์‹ธ์ ธ์žˆ์œผ๋ฉด SpEL๋กœ ํŒŒ์‹ฑํ•˜๊ณ  ํ‰๊ฐ€(์‹คํ–‰)ํ•ด์„œ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ๋‹ค.

 

SpEL๊ณผ ํ”„๋กœํผํ‹ฐ

SpEL์€ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฐ˜๋Œ€๋Š” ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

 

ํ”„๋กœํผํ‹ฐ

 

1
2
3
4
5
6
7
@Value("#{'${my.value}' eq '100'}")
boolean isEqual;
 
@Override
public void run(ApplicationArguments args) throws Exception {
    System.out.println(isEqual);
}
cs

 

์‹คํ–‰ ๊ฒฐ๊ณผ

true

 

Bean Reference(๋นˆ ์ฐธ์กฐ) ๋ฐฉ๋ฒ•

#{๋นˆid.ํ”„๋กœํผํ‹ฐ} ํ˜•์‹์œผ๋กœ ์ฐธ์กฐํ•œ๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.stereotype.Component;
 
@Component
public class Sample {
    
    private int value = 123;
 
    public int getValue() {
        return value;
    }
}
cs

 

1
2
3
4
5
6
7
@Value("#{sample.Value}")
int sampleValue;
 
@Override
public void run(ApplicationArguments args) throws Exception {
    System.out.println(sampleValue);
}
cs

 

์‹คํ–‰ ๊ฒฐ๊ณผ

123

 

Expression์„ ์ด์šฉํ•œ SpEL ํŒŒ์‹ฑ

1
2
3
4
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("1+1");
Object value = expression.getValue();
System.out.println(value);    // 2
cs

ExpressionParser์˜ ๊ตฌํ˜„์ฒด SpelExpressionParser๋กœ SpEL์˜ ๋‚ด์šฉ์„ ํŒŒ์‹ฑ(Parsing) ํ•˜๊ณ  Expression์˜ getValue() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ํŒŒ์‹ฑ๋œ ๊ฒฐ๊ณผ๊ฐ’์„ Object ํƒ€์ž…์œผ๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

 

1
2
3
4
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("1+1");
int value = expression.getValue(Integer.class);
System.out.println(value);  // 2
cs

getValue() ํ˜ธ์ถœ ์‹œ Class์ •๋ณด๋ฅผ ๋„˜๊ธฐ๋ฉด ์ž๋™์œผ๋กœ ํƒ€์ž… ์บ์ŠคํŒ…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

EvaluationContext๋ฅผ ์ด์šฉํ•œ SpEL ํŒŒ์‹ฑ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// name, nationality๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๊ฐ–๋Š” ์ƒ์„ฑ์ž
Inventor tesla = new Inventor("Nikola Tesla","Serbian");
 
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name"); // name ํ”„๋กœํผํ‹ฐ
 
// Context์— tesla๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.
EvaluationContext context = new StandardEvaluationContext(tesla);
String name1 = (String) exp.getValue(context); //name = "Nikola Tesla"
System.out.println(name1);  // Nikola Tesla
 
// getValue ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ StandardEvaluationContext๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ง€์ •
String name2 = (String) exp.getValue(tesla);
System.out.println(name2);  // Nikola Tesla
cs

StandardEvaluationContext์— name ํ”„๋กœํผํ‹ฐ๊ฐ€ ํ‰๊ฐ€ ๋  ๊ฐ์ฒด๋ฅผ ์ง€์ •ํ•œ๋‹ค. (name1)

StandardEvaluationContext๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  getValue()์— ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.(name2)

 

StandardEvaluationContext๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ƒ์„ฑ ๋น„์šฉ์ด ๋ฐœ์ƒํ•˜์ง€๋งŒ ํ•„๋“œ์— ๋Œ€ํ•ด ์บ์‹ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ํ‘œํ˜„์‹ ํŒŒ์‹ฑ์ด ๋” ๋น ๋ฅด๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

๐Ÿ’ก SpEL๋„ ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ ConversionService๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

 

References

์ธํ”„๋Ÿฐ - ๋ฐฑ๊ธฐ์„ ๋‹˜์˜ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ ํ•ต์‹ฌ ๊ธฐ์ˆ 

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions

https://jaehun2841.github.io/2018/11/21/2018-11-21-spel-expression

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€