ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [14] Spring Expression Language (SpEL)
    Spring/Spring 핵심 기술 2020. 4. 29. 09:42
    반응형

    Spring Expression Language는 객체 graph[각주:1]를 조회하고 조작하는 기능을 제공하는 expression language입니다. method 호출과 문자열 template 기능을 제공하며 Spring project 전반에 걸쳐 사용할 목적으로 만들어졌습니다.

     

    SpEL의 구성

    • ExpressionParser parser = new SpelExpressionParser()
    • StandardEvaluationContext context = new Standard EvaluationContext (bean)-->EvalucationContext를 통해 등록된 bean의 method는 SpEL을 통해 접근할 수 있습니다.
    • Expression expression = parser.parseExpression(“SpEL 표현식”)
    • String value = expression.getvalue(context, String.class)

     


     

     

    [SpEL의 사용의 예]

     

    예제에서 property를 가져와야 하므로 먼저 property를 하나 만들어 둡니다. 여기서는 resources\application.properties를 사용하도록 합니다.

    my.value=100

     

    bean의 data를 가져올 수 있음을 확인하기 위한 class(Sample.java)도 하나 작성합니다.

    @Component
    public class Sample {
    
        private int data = 300;
    
        public int getData() {
            return data;
        }
    
        public void setData(int data) {
            this.data = data;
        }
    }

     

    SpEL 사용을 확인하기 위해 Runner class(AppRunner.java)를 다음과 같이 작성합니다.

    @Component
    public class AppRunner implements ApplicationRunner {
    
        @Value("#{1 + 1}")   //	①
        int value;
    
        @Value("#{'Hello ' + 'world'}")
        String greeting;
    
        @Value("#{1 eq 1}")
        boolean trueOrFalse;
    
        @Value("${my.value}")	//	②
        int myValue;
    
        @Value("#{${my.value} + 100}")	//	③
        int myValue2;
    
        @Value("#{sample.data}")    //  ④
        int sampleData;
    
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            System.out.println("=================================");
            System.out.println("value       : " + value);
            System.out.println("greeting    : " + greeting);
            System.out.println("trueOrFalse : " + trueOrFalse);
            System.out.println("myValue     : " + myValue);
            System.out.println("myValue2    : " + myValue2);
            System.out.println("sampleData  : " + sampleData);
        }
    }

    @Value annotation은 annotation이 지정된 filed에 value 값을 그대로 전달하는 annotation입니다. SpEL 표현식은 "#{표현식}" 형태입니다.

    ②SpEL에서 property에 접근하여 값을 가져오려면 "${가져올 property}"형태의 문법을 사용합니다.

    ③표현식 안에 property를 넣어 사용할 수 있습니다. 반대로 property 안에 표현식을 넣을 수는 없습니다.

    ④표현식을 통해 bean의 field를 가져올 수 있습니다. field는 bean의 name을 통해 접근합니다. bean의 name은 통상 bean의 Class명을 smallcase로 시작한 것입니다.

     

     

    실행결과는 다음과 같습니다.

    실행결과

     

     

    보다 상세한 문법은 reference를 참고합니다.


    [SpEL의 실제 사용]

    SpEL은 @Value annotation 외에도 여러군데서 사용되고 있습니다.

     

    @ConditionalOnExpression : 선택적으로 bean을 등록하거나 bean 설정 file을 읽는 annotation으로 SpEL을 사용하여 선별적 bean 등록이 가능합니다.

     

    Spring Security : EvaluationContext를 통해 hasRole(), hasIpAddress() 등의 security관련 method를 가진 bean을  만들고 @PreAuthorize, @PostAuthorize, @PreFilter, @PostFilter 등의 annotation 안에서 SpEL로 해당 method를 호출할 수 있습니다.

     

    Spring Data : @Query annotation이 적용된 method의 parameter를 @Query annotation의 value에서 접근할 때 SpEL을 사용합니다.

    @Query("select u from User u where u.age = ?#{[0]}")
    List<User> findUsersByAge(int age);
    
    @Query("select u from User u where u.firstname = :#{#customer.firstname}")
    List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);
    
    @Query("select u from User u where u.emailAddress = ?#{principal.emailAddress}")
    List<User> findCurrentUserWithCustomQuery();

     

    Thymeleaf (Template engine) : Template engine에서도 SpEL을 사용할 수 있습니다.

    #{T(kr.ne.outsider.Codes).values()}	//Enum 전체를 가져오기
    #{T(kr.ne.outsider.Codes).ERROR}	//특정 Enum을 가져오기
    #{T(kr.ne.outsider.Codes).MESSAGE}
    
    #{T(kr.ne.outsider$Codes).ERROR}	//Static 상수에 접근하기. Enum이 static으로 정의된 경우 $를 사용하여 접근

     


     

    [Expression Parser를 직접 사용]

    parser를 생성하여 표현식을 지정 후 값을 가져오는 예입니다. runner class(AppRunner.java)를 다음과 같이 수정 후 실행해 봅니다.

    @Component
    public class AppRunner implements ApplicationRunner {
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
        
            ExpressionParser parser = new SpelExpressionParser();	//	①
            Expression expression =  parser.parseExpression("2 + 100");	//	②
            Integer value = expression.getValue(Integer.class); //	③
            System.out.println(value);
        }
    }

    ① ExpressionParser 객체를 생성합니다.

    ② ExpressionParser 객체의 parseExpression() method를 통해 표현식을 지정하여 Expression 객체를 생성합니다.

    ③ Expression 객체에 getValue() method를 통해 표현식의 값을 가져옵니다. 표현식에 대한 결과는 String type이며 만약 다른 type으로 받아야 하는 경우 getValue()의 parameter로 받을 type의 class를 지정합니다. 이때 type간 변환은 ConversionService를 사용하게 됩니다.

    1. 객체 graph란?
      객체지향 프로그래밍에서 각각의 객체들은 주어진 역할과 책임을 감당하기 위해 다른 객체들을 참조하며 유기적인 관계를 맺고 있습니다. 이렇게 참조를 통한 관계로 묶인 객체들의 group을 객체 graph라고 합니다.  [본문으로]

    댓글

Designed by Tistory.