본문 바로가기
spring & spring boot

Spring Boot @ConfigurationProperties

by shakevan 2022. 7. 14.

요약

  1. Spring Boot 2.2 버전을 기점으로 ConfigurationProperties에 대한 사용성이 많이 변경됨
    • Spring Boot 2.2버전 미만은 @Component + @ConfigurationProperties를 활용
    • Spring Boot 2.2버전 이상은 @ConfigurationPropertiesScan + @ConfigurationProperties를 활용 (불변을 원한다면 @ConstructorBinding 추가)

아래 글은 Spring Boot 2.7.1에서 테스트한 내용을 기반으로 하고 있으며, 


Spring Boot 2.2 버전 미만에서는 동작하지 않을 수 있습니다.

설명

  • 외부 설정을 주입받을 때 사용
  • 주로 application.properties, application.yml에 있는 설정파일을 주입받을 경우가 많음
  • @ConfigurationPropertiesScan을 통해 @ConfigurationProperties 어노테이션이 붙어있는 클래스 or 함수에 값을 바인딩 해줌
//application.yml
van:
  test: sunho


//Application.class

/**
 * Application class에 @ConfigurationPropertiesScan을 선언해서 해당 클래스 하위의 모든 패키지들을 Scan
 */
@ConfigurationPropertiesScan
@SpringBootApplication
class Application


/**
 * van으로 시작하는 property들을 바인딩
 */
@ConfigurationProperties(prefix = "van")
class VanConfig(
    var test: String = "a"
)
  • 다만 위와 같은 방식은 test가 가변이면서, notNull을 보장하기위한 default인자가 반드시 필요하다.
    • ConfigurationProperties은 기본적으로 Setter로 값을 바인딩하기 때문
  • 위와 같은 아쉬움을 해결하기 위해 @ConstructorBinding을 통해 생성자를 통한 바인딩을 할 수 있다.
/**
 * ... 위와 동일
 */

/**
 * van으로 시작하는 property들을 생성자를 통해 바인딩
 */
@ConstructorBinding
@ConfigurationProperties(prefix = "van")
class VanConfig(
    var test: String = "a"
)
  • Bean어노테이션과도 함께 사용 가능
//application.yml
van:
  test: sunho

//Application.class

/**
 * Application class에 @ConfigurationPropertiesScan을 선언해서 해당 클래스 하위의 모든 패키지들을 Scan
 */
@ConfigurationPropertiesScan
@SpringBootApplication
class Application

/**
 * 일반 class 생성
 */
class VanProperties(
    var test: String = "a",
    val a: String,
    val b: String
) {
    companion object {
        fun create(): VanProperties {
            return VanProperties(a = "hello", b = "van", test = "에베베베베")
        }
    }
}

@Configuration
class VanConfiguration {
    /**
     * 객체 생성 후 (test에 에베베베베라는 값 할당)
     * 값 바인딩 (application.yml 에 있는 van.test = sunho)
     */
    @Bean
    @ConfigurationProperties("van")
    fun vanProperties(): VanProperties {
        return VanProperties.create()
    }
}

@Component
class Runner(
    private val van: VanProperties
) : ApplicationRunner {
    override fun run(args: ApplicationArguments?) {
        println("a is ${van.a}")
        println("b is ${van.b}")
        /**
         * 에베베베베가 아닌 sunho가 출력된다
         */
        println("test is ${van.test}")
    }
}

실제 사용

요구사항 1) Spring Boot의 DataSource를 HikariDataSource가 아닌 LazyConnectionDataSourceProxy로 변경

  • LazyConnectionDataSourceProxy 사용하는 이유는 TBD
//application.yml

spring:
  datasource:
    hikari:
      driver-class-name: org.h2.Driver
      jdbc-url: jdbc:h2:mem://localhost/~/testdb;MODE=MYSQL
      username: sa
      password:
//DataBaseConfiguration.kt

@Configuration
class DataBaseConfiguration {

    /**
     * application.yml에 설정된 spring.datasource.hikari값들을 바인딩
     */
    @Bean
    @ConfigurationProperties("spring.datasource.hikari")
    fun hikariConfig(): HikariConfig {
        return HikariConfig()
    }

    /**
     * hikariConfig를 기반으로 HikariDataSoure를 생성 후 LazyConnectionDataSourceProxy 생성
     */
    @Bean
    fun dataSource(hikariConfig: HikariConfig): DataSource {
        val hikariDataSource = HikariDataSource(hikariConfig)
        return LazyConnectionDataSourceProxy(hikariDataSource)
    }
}

요구사항 2) google에 호출해야하는 api List들을 Properties로 관리

//application.yml
api:
  google:
    host: https://google.co.kr
    headers:
      Authorization: hello
      Cookie: hh
      customAuth: customAuth
    endpoints:
      users: /users
      login: /login
      logout: /logout
// GoogleApiProperties.kt
/**
 * 불변으로 하기위해 @ConstructorBinding
 */
@ConstructorBinding
@ConfigurationProperties("api.google")
data class GoogleApiProperties(
    private val host: String,
    // headers는 key,value 매핑
    private val headers: Map<String, String>,
    private val endpoints: EndpointProperties
)

data class EndpointProperties(
    private val users: String,
    private val login: String,
    private val logout: String
)

참고

  1. EnableConfigurationProperties를 선언하지 않아도 되는 이유
  2. Guide to @ConfigurationProperties in Spring Boot
  3. Spring Boot 공식 문서 7.2.8. Type-safe Configuration Properties

댓글