본문 바로가기
Java/Spring

[12] 스프링 프레임워크 핵심 - SPEL, Null Safety

by Riverandeye 2020. 12. 16.

해당 글은 백기선의 스프링 프레임워크 핵심 강좌를 듣고 정리한 것입니다. 

 

SPEL

SPEL은 객체 그래프를 조회하고 조작하는 기능을 제공합니다. 

Expression Language  의 기능 및 메소드 호출, 문자열 템플릿 기능을 제공해야 하는 경우에 사용됩니다. 

 

    @Value("#{1 + 1}")
    int value;

    @Value("#{'hello ' + 'world'}")
    String greeting;

    @Value("#{1 eq 1}")
    boolean trueOrFalse;

다음과 같이, Value annotation의 String 값에 표현식으로 넣을 수 있습니다. 

 

헷갈리는 부분은 # 와 $의 차이인데요

#{..}는 Spel 문법으로, property placeholder syntax도 Spel 문법 내에서 사용할 수 있습니다. 

${..}는 property placeholder syntax로, 지정되어 있는 property를 꺼내 사용하는 경우에만 쓸 수 있으며, Spel 문법이 작동하지 않습니다.

외부에서 지정된 property를 주입하고 싶은 경우에 ${}를 사용하면 되고, 이를 이용해 다른 연산을 수행하고 싶을때 Spel을 사용합니다.

 

Spel로 어디까지 할 수 있냐에 대해 예시를 대표적으로 들어보면

// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length"); 
int length = (Integer) exp.getValue();

위와 같이 문자열의 길이를 알 수도 있고

 

@Value("#{new String('hello world').toUpperCase()}")
String greeting;

위와 같이 String을 만들 수도 있고, 다양합니다. 

구체적인 것들은 docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions를 참고하면 될 것입니다. 

메서드를 호출할 수도 있지만, 잘 쓰지는 않는데 필요할 경우도 있어서 레퍼런스를 참고하여 사용합니다. 

 

주로 @Value 어노테이션이나

@ConditionalOnExpression 과 같이 선택적으로 Bean을 등록하거나 설정파일을 읽어올 수 있는 기능을 사용할 때

Spel을 사용할 수 있습니다.

 

스프링단에서 쓰게 되면 저렇게 단순하지만, 

실제 동작은, ExpressionParser를 통해 문자열을 파싱하고,

EvaluationContext를 통해 파싱된 결과물을 특정 Context에 대해 분석하여

분석한 결과물을 특정 Class의 값으로 Convert 하게 됩니다. 

Convert 할 때는 내부적으로 ConversionService를 사용하게 됩니다.

 

ExpressionParser parser = new SpelExpressionParser()
StandardEvaluationContext context = new StandardEvaluationContext(bean)
Expression expression = parser.parseExpression(“SpEL 표현식”)
String value = expression.getvalue(context, String.class)

 

Null Safety

스프링 프레임워크 5에 추가된 Null 관련 어노테이션들이 여러가지 있습니다. 

@NonNull
@Nullable
@NonNullApi (패키지 레벨 설정)
@NonNullFields (패키지 레벨 설정)

Null을 허용하느냐 허용하지 않느냐를 Annotation으로 마킹하고

Intellij와 같은 툴의 도움을 받아 컴파일 시간에 NullPointerException을 미연에 방지할 수 있습니다. 

문제는 아무 설정도 안하면 안되고, Compiler Option에서 특정한 설정을 해주어야합니다.

 

Preferences > Build, Execution, Deployment > Compiler > Configure annotations... 를 누르면

 

Configure annotations
Null 관련 어노테이션

Intellij runtime에 notnull-annotation에 대한 assertion이 적용되는 어노테이션들을 지정할 수 있는데요

위에 등록된 어노테이션들만 intellij에 감지가 됩니다.

기본 설정은 Spring에 관한 어노테이션이 없는 상황이다 보니 이를 추가해야 합니다.

 

위아래가 나뉘어져 있는데, 위에 것은 Nullable annotation이고 아래 것은 NotNull annotation 입니다.

어노테이션 목록의 좌측 상단부 + 버튼을 누르면 다음과 같이 나타나는데요

 

위에 것을 선택하였으니 Nullable을 등록해야 합니다.

springframework의 Nullable을 추가해줍니다. 

 

springframework Nullable

 

밑에 + 버튼을 눌러 NonNull 도 추가해줍니다. 

 

springframework NonNull

그럼 다음과 같이 NonNull 인자를 추가한 경우 

public String createBook(@NonNull String bookName){
	return bookName;
}

 

컴파일 시점에 다음과 같이 null 이 주입되면 안됨을 확인할 수 있습니다.

null 입력에 대한 경고

 

만약 리턴값이 null이 아니게끔 강제하고 싶으면 다음과 같이 메소드에 어노테이션을 붙여줍니다. 

@NonNull

저렇게 매 api 마다 @NonNull을 붙이기 번거로운 경우

패키지 단위로 설정할 수도 있습니다. 

 

package-info.java 파일을 생성해서

해당 패키지 선언부 위에 어노테이션을 붙여서 사용하면 됩니다. 

 

@NonNullApi
@NonNullFields
package riverandeye.autowired;

import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

 

댓글