Baeldung - A Quick Guide to Spring @Value

sycho·2024년 3월 24일
0

Baeldung - Spring Tutorial

목록 보기
12/14

Baeldung의 이 글을 정리 및 추가 정보를 넣은 글입니다.

1. Overview

  • 이전 글에 언급했듯 이번에는 @Value에 대해서 알아보도록 하겠다.

  • 그때는 속성값들을 Spring에서 관리하는 bean의 field에 주입하는 용도로 사용되었었는데 실제로 그 용도로 주로 사용된다. 다만 단순 field뿐만 아니라 생성자나 메서드의 parameter에 주입하는 것도 가능하다.

2. Setting Up the Application

  • 관련 예제들을 실제로 사용해보려면 준비해야하는 파일들이 있다. 바로 property들을 정의한 파일, 즉 property file.

  • 이에 대해서는 이전 글에서 자세히 다뤘다. 순수 Spring이면 @PropertySource annotation에 property 설정 파일을 적어서 @Configuration class에다가 설정해줘야 하고, Spring Boot라면 그냥 application.properties에 집어넣으면 된다. 다른 방법들은 앞에 링크한 글 참고. 이 글의 경우 밑과 같은 property file을 사용했다.

value.from.file=Value got from the file
priority=high
listOfValues=A,B,C

3. Usage Examples

  • @Value로는 먼저 단순 String value를 직접 작성해가지고 field에 주입하는 것이 가능하다. 밑은 stringValue"string value"를 주입하는 코드다.
@Value("string value")
private String stringValue;
  • 그리고 앞에서 말한 방식으로 현 Environment에 property들을 등록했으면 밑과 같이 ${...} 플레이스홀더를 사용해서 property 값을 주입하는 것이 가능하다. 밑은 property file의 value.from.file값, 즉 "Value got from the file"stringValue에 주입하는 코드다.
@Value("${value.from.file}")
private String valueFromFile;
  • ${...}에 있는 property 값이 Environment상에 정의되지 않았을 때 사용할 기본값도 설정이 가능하다. :를 사용하면 된다. 밑의 경우 unknown.param이 정의되지 않은 property라 some default라는 값이 someDefault라는 field에 주입된다.
@Value("${unknown.param:some default}")
private String someDefault;
  • 또 JVM 구동시 자동으로 설정되는 System Property라는 것이 있는데, 이 property들도 Environment에 등록되기에 @Value를 사용해서 접근하는 것이 가능하다. 유의할건, 만약 system property와 property file에서 둘 다 정의한 property가 있으면 해당 property 주입 시 system property의 것이 사용된다는 것이다.

  • 마지막으로 배열에 주입하는 경우를 생각해보자. 이 경우 여러개의 값들을 한번에 주입하는 방법이 있으면 좋을 것이고... 실제로 이게 가능하다. 앞의 property file에서 listOfValues를 보면 쉼표로 구별된 값들을 볼 수 있는데, 이 property를 배열에 넣으면 자동으로 쉼표로 구별된 element 개수만큼의 배열이 만들어지게 된다. 즉 밑의 경우 ["A", "B", "C"]라는 값이 valuesArray에 주입된다.

@Value("${listOfValues}")
private String[] valuesArray;

4. Advanced Examples With SpEL

  • SpEL은 Spring Expression Language의 줄임말이다. 관련 documentation 여기선 이에 대해 자세히 다루지는 않고 @Value에서 이를 어떻게 활용하는지 몇가지 예제만 보도록 하겠다.

  • 밑과 같은 SpEl을 사용하면 priority라는 system property가 존재시 해당 값을 spelValue에 주입한다.

@Value("#{systemProperties['priority']}")
private String spelValue;
  • 밑과 같은 SpEL을 사용하면 unknown이라는 system property가 존재시 해당 값을, 아닌 경우 'some default'spelSomeDefault에 주입한다.
@Value("#{systemProperties['unknown'] ?: 'some default'}")
private String spelSomeDefault;
  • 밑과 같은 SpEL을 사용하면 someBean이라는 bean의 someValue라는 값을 someBeanValue에 주입하는 것이 가능하다.
@Value("#{someBean.someValue}")
private Integer someBeanValue;
  • 마지막으로 밑과 같은 SpEL을 활용해서 3번의 마지막 부분처럼List를 형성하는 것도 가능하다.
@Value("#{'${listOfValues}'.split(',')}")
private List<String> valuesList;

5. Using @Value With Maps

  • @ValueMap에 해당하는 field를 집어넣거나, Map안의 특정 원소들을 집어넣는 것도 가능하다. 먼저 property file에 다음과 같은 property가 정의되어 있다고 해보자. 유의할건, Map안의 value들을 설정할 때 작은따옴표를 써야 한다는 것이다. 큰따옴표나 아무 따옴표 없이 value를 표현하면 안된다.
valuesMap={key1: '1', key2: '2', key3: '3'}
  • Map type의 field에 주입하는 방법은 다음과 같다. SpEL을 활용한다.
@Value("#{${valuesMap}}")
private Map<String, Integer> valuesMap;
  • Map 안의 특정 key에 대응되는 value를 주입하는 방법은 다음과 같다. 밑은 key1에 해당하는 값을 주입한다.
@Value("#{${valuesMap}.key1}")
private Integer valuesMapKey1;
  • Map 안에 특정 key가 존재하는지 확실하지 않을 경우 존재하지 않으면 exception을 반환하는게 아닌, 해당 값을 null로 설정하도록 하는 SpEL expression이 존재한다. 밑은 unknownKey가 존재하지 않을 경우 unknownMapKeynull값을 저장한다.
@Value("#{${valuesMap}['unknownKey']}")
private Integer unknownMapKey;
  • Map을 주입하는 경우든, Map의 특정 key에 대응되는 value를 주입하는 경우든 값이 존재하지 않을 경우 집어 넣을 기본값을 설정하는 것이 SpEL에서 가능하다.
@Value("#{${unknownMap : {key1: '1', key2: '2'}}}")
private Map<String, Integer> unknownMap;

@Value("#{${valuesMap}['unknownKey'] ?: 5}")
private Integer unknownMapKeyWithDefaultValue;
  • Map을 주입하는 경우, Map 안에서 특정 조건 만족을 하는 key-value pair만 집어넣는 것이 가능하다. 여기선 조건 비교를 key-value의 value로만 했지만 key로 하는 것도 가능하다. 이 경우 key를 사용.
@Value("#{${valuesMap}.?[value>'1']}")
private Map<String, Integer> valuesMapFiltered;
  • 참고로 알만한 것으로 모든 system properties를 Map의 형태로 주입하는 것이 가능하다.
@Value("#{systemProperties}")
private Map<String, String> systemPropertiesMap;

6. Using @Value Wtih Constructor Injection

  • 생성자의 parameter에 값을 주입할 때도 사용이 가능하다. 밑은 PriorityProvider이라는 bean 형성 때 사용되는 생성자의 priority parameter에 priority라는 성분을 주입, 만약 해당 성분이 values.properties에 없는 경우 normal이라는 String을 주입하라는 코드다. 이러면 PriorityProvider bean은 priority 성분이 존재시 해당 값을 priority field에 저장하게 되고, 존재하지 않으면 normal이라는 값을 priority field에 저장하게 된다.
@Component
@PropertySource("classpath:values.properties")
public class PriorityProvider {

    private String priority;

    @Autowired
    public PriorityProvider(@Value("${priority:normal}") String priority) {
        this.priority = priority;
    }

    // standard getter
}

7. Using @Value With Setter Injection

  • 앞의 생성자랑 비슷하게 setter에다가 적용하는 것도 가능하다. 밑은 values.properties에 있는 listOfValues의 값들을 List 형태로 values에 주입한다. 구분자는 ,. 만약 해당 값이 없을 경우 오류가 나온다.
@Component
@PropertySource("classpath:values.properties")
public class CollectionProvider {

    private List<String> values = new ArrayList<>();

    @Autowired
    public void setValues(@Value("#{'${listOfValues}'.split(',')}") List<String> values) {
        this.values.addAll(values);
    }

    // standard getter
}

8. Using @Value With Records

@Component
@PropertySource("classpath:values.properties")
public record PriorityRecord(@Value("${priority:normal}") String priority) {}
profile
안 흔하고 싶은 개발자. 관심 분야 : 임베디드/컴퓨터 시스템 및 아키텍처/웹/AI

0개의 댓글