[활용]_04_외부 설정 2부

2 minute read

외부 설정 2부

타입-세이프 프로퍼티 @ConfigurationProperties

  • 여러 프로퍼티를 묶어서 읽어올 수 있음
  • 빈으로 등록해서 다른 빈에 주입할 수 있음
    • @EnableConfigurationProperties
    • @Component
    • @Bean
  • 융통성 있는 바인딩(Relaxed Binding)
    • context-path (케밥)
    • context_path (언드스코어)
    • contextPath (캐멀)
    • CONTEXTPATH
  • 프로퍼티 타입 컨버전
    • @DurationUnit
  • 프로퍼티 값 검증
    • @Validated
    • JSR-303 (@NotNull, …)
  • 메타 정보 생성

  • @Value
    • SpEL 을 사용할 수 있지만…
    • 위에 있는 기능들은 전부 사용 못합니다.

타입-세이프 프로퍼티 @ConfigurationProperties

같은 키로 시작하는 외부 설정의 경우 묶어서 하나의 빈으로 등록할 수 있다.

  1. 빈으로 만들 클래스를 하나 생성

  2. 속성 key 값들을 변수로 선언
  3. Getter, Setter 추가
    • 자바 빈 스펙을 따라서 (properties 값을 클래스 변수에) 자동으로 바인딩을 해주기 때문에

메타 정보 추가

  1. @ConfigurationProperties(key값) 어노테이션 추가

    • “Configuration Annotation Processor not configured” 에러

      ⇒ 이 어노테이션이 달려있는 클래스를 분석해서 메타정보를 만들 수 있다.

      properties에서 자동완성기능은 메타정보를 기반으로 해서 이루어진다.

      프로젝트를 빌드할 때 이러한 메타정보를 생성해주는 플러그인을 추가하라고 알려주는 것이다.

  2. 플러그인 의존성 추가

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

소스코드

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("person")
public class PersonProperties {

    private String name;

    private int age;

    private String fullName;

    public String getName() {
        return name;
    }

    // ... getter , setter 추가 ...
}
  1. 바인딩한 값을 사용할 수 있도록 빈으로 등록 (기본설정으로 이미 활성화되어있음)
  • @EnableConfigurationProperties(Configuration properties 클래스) 어노테이션 추가

Configuration Properties 에 대한 목록을 지정해줘야 한다.

빈으로 등록해주고 @ConfigurationProperties어노테이션을 처리해준다.

@SpringBootApplication
@EnableConfigurationProperties(PersonProperties.class) // <-- 목록 추가
public class SpringinitApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(SpringinitApplication.class);
        app.run(args);
    }
}
  • @Component 어노테이션 추가 : PersonProperties클래스를 빈으로 등록
@Component //<-- 빈으로 등록
@ConfigurationProperties("person")
public class PersonProperties { ... }

빈으로 등록한 외부 설정 사용하기

  • @Autowired로 빈을 주입받아서 사용
@Component
public class SampleRunner implements ApplicationRunner {

    @Autowired
    PersonProperties personProperties;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("=============================");
        System.out.println(personProperties.getFullName());
        System.out.println(personProperties.getAge());
        System.out.println("=============================");
    }
}
=============================
Bolar Kim
23
=============================

외부 파일을 빈으로 등록

properties가 어플리케이션 내부에 있는 것이 아니라 외부에 있는 경우 (ex. jar 파일) 클래스위에 @Component 어노테이션을 붙일 수 없다. 이런 경우 @Bean이 붙어있는 위치 위에 @ConfigurationProperties 어노테이션을 이용하면 된다.

스프링이 제공하는 프로퍼티들은 전부 기본적으로 빈으로 주입받아서 사용가능하다. (이미 바인딩된 값이 들어옴)

@SpringBootApplication
public class SpringinitApplication {

    @ConfigurationProperties("server")
    @Bean
    public ServerProperties serverProperties() {
        return new ServerProperties();
    }

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(SpringinitApplication.class);
        app.run(args);
    }
}

융통성 있는 바인딩(Relaxed Binding)

  • context-path (케밥)
  • context_path (언드스코어)
  • contextPath (캐멀)
  • CONTEXTPATH

properties에 변수 이름을 위 목록의 어떠한 케이스를 사용하더라도 바인딩 해준다.

프로퍼티 타입 컨버전

  • 스프링이 타입 컨버젼 서비스를 제공

properties에서는 타입이라고 할 것이 없이 문자열로 값을 넣는다.

person.name = solar
person.age = 100

이러한 값들이 기본적으로 각 타입에 맞게 컨버팅이 돼서 들어간다.

public class PersonProperties {
    private String name;
    private int age;	// 타입 컨버팅이 자동으로 된다.
  ...
}
@DurationUnit
  • 시간 정보를 제공하는 타입 컨버젼

application.properties

person.sessionTimeout = 25

PersonProperties.java

@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30); // 기본값은 30초로 지정

// getter, setter 추가

⇒ 문자 25를 Duration 타입으로 컨버젼해준다.

또는, 다음과 같이 문자형숫자값 뒤에 s를 붙이면 자동으로 Duration 타입으로 컨버젼 해준다.

person.sessionTimeout = 25s

이러한 suffix가 여러가지 있다.

프로퍼티 값 검증

  • @Validated
  • JSR-303 (@NotNull, @Size(min = xx) …)

JSR-303이라는 Validation API의 구현체인 하이버네이트 Validation API를 사용

( spring-boot-starter-web 하위에 들어와 있던데 없어서 추가 해줌)

<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>6.1.0.Final</version>
</dependency>
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DurationUnit;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.time.Duration;
import java.time.temporal.ChronoUnit;

@Component
@ConfigurationProperties("person")
@Validated	// 어노테이션 추가
public class PersonProperties {

    @NotEmpty // 검증할 내용
    private String name;

    @Size(min = 20, max = 100) // 이 부분은 binding 실패에러남... 왜지
    private int age;

    private String fullName;
 //...
}

@Value

  • SpEL 을 사용할 수 있지만…
  • 위에 있는 기능들은 전부 사용 못합니다.
    • 예로 융통성 있는 바인딩(Relaxed Binding)을 지원하지 않기때문에 정확하게 적어줘야 한다.
    • 메타정보를 제공하지도 않는다.