Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ihoneymon/de5207686da74f60d8973f20e87b3897 to your computer and use it in GitHub Desktop.
Save ihoneymon/de5207686da74f60d8973f20e87b3897 to your computer and use it in GitHub Desktop.
스프링 부트 구성파일 데이터 적재 간단설명

스프링 부트 구성속성 이용(Spring Boot External Configuration)

스프링 부트에서는 애플리케이션에서 필요한 속성을 "애플리케이션 구성파일" application.yml(혹은 applicatoin.properties) 에 작성하여 활용합니다.

Note

데이터구조를 계층형으로 표현할 수 있어서 개인적으로 .properties 파일 보다는 .yml(YAML) 파일 이용을 선호합니다.

.yaml .properties
environments:
  dev:
    url: "https://dev.example.com"
    name: "Developer Setup"
  prod:
    url: "https://another.example.com"
    name: "My Cool App"
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
my:
 servers:
 - "dev.example.com"
 - "another.example.com"
my.servers[0]=dev.example.com
my.servers[1]=another.example.com

이렇게 표현식을 비교해봤을 때 보다 눈에 잘 들어오는 편입니다(가독성이 높다라고 생각합니다).

그리고 이런 표현식을 이용해서 application.yml 에 다음과 같이 활용할 수 있습니다. application-keycloak.yml 를 작성해보겠습니다.

Note

스프링 부트 2.4 부터 애플리케이션 구성파일(application.yml ) 적재방식이 변경되었습니다.

application.yml
spring:
    profiles:
        group:
            local: "keycloak-local, db-local"
            dev: "keycloak-deve, db-dev"
            beta: "keycloak-beta, db-beta"
            prod: "keycloak-prod, db-prod"
        include: "keycloak"
application-keycloak.yml
spring:
  config:
    activate:
      on-profile: "keycloak-local,keycloak-test"
keycloak:
  url: "https://test-keycloak.localtest.com"
  username: "honeymon-local"
  password: "password-local"
  store-maps:
    "DEFAULT_REALM": "honeymon-local"
    "DEFAULT_TOPIC": "topic"
---
spring:
  config:
    activate:
      on-profile: "keycloak-dev"
keycloak:
  url: "https://test-keycloak.devtest.com"
  username: "honeymon-dev"
  password: "password-dev"
  store-maps:
    "DEFAULT_REALM": "honeymon-dev"
    "DEFAULT_TOPIC": "topic-dev"
---
spring:
  config:
    activate:
      on-profile: "keycloak-beta"
keycloak:
  url: "https://test-keycloak.betatest.com"
  username: "honeymon-beta"
  password: "password-beta"
  store-maps:
    "DEFAULT_REALM": "honeymon-beta"
    "DEFAULT_TOPIC": "topic-beta"
---
spring:
  config:
    activate:
      on-profile: "keycloak-prod"
keycloak:
  url: "https://test-keycloak.test.com"
  username: "honeymon-prod"
  password: "password-prod"
  store-maps:
    "DEFAULT_REALM": "honeymon-prod"
    "DEFAULT_TOPIC": "topic-prod"

다음과 같이 작성된 application-keycloak.yml 에 대응하는 @ConfigurationProperties 클래스를 다음과 같이 작성했습니다.

KeyCloakConfigurationProperties
@Getter
@ConfigurationProperties("keycloak")
public class KeyCloakConfigurationProperties {
    private final String url;
    private final String username;
    private final String password;
    private final Map<String, String> storeMaps;

    @ConstructorBinding
    public KeyCloakConfigurationProperties(String url, String username, String password, Map<String, String> storeMaps) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.storeMaps = storeMaps;
    }
}

이렇게 작성된 @ConfigurationProperties 클래스는 spring-boot-configuration-processor 를 이용하면 개발도구에서 자동완성에 이용할 수 있는 META-INF/spring-configuration-metadata.json 를 생성할 수 있습니다.

Note

보다 자세한 내용은 "스프링 부트 참고문서#Appendix B: Configuration Metadata"를 살펴시기 바랍니다.

작성된 @ConfigurationProperties 클래스 KeyCloakConfigurationProperties 는 다음과 같은 방식으로 테스트할 수 있습니다.

//KeyCloakConfigurationPropertiesDevTest
@ActiveProfiles("dev")
@SpringBootTest
class KeyCloakConfigurationPropertiesDevTest {
    @Autowired
    KeyCloakConfigurationProperties keyCloakConfigurationProperties;

    @Test
    void testProperty() {
        SoftAssertions.assertSoftly(softly -> {
            softly.assertThat(keyCloakConfigurationProperties.getUrl()).isEqualTo("https://test-keycloak.devtest.com");
            softly.assertThat(keyCloakConfigurationProperties.getUsername()).isEqualTo("honeymon-dev");
            softly.assertThat(keyCloakConfigurationProperties.getPassword()).isEqualTo("password-dev");
            softly.assertThat(keyCloakConfigurationProperties.getStoreMaps().get("DEFAULT_REALM")).isEqualTo("honeymon-dev");
        });
    }
}

//KeyCloakConfigurationPropertiesBetaTest
@ActiveProfiles("beta")
@SpringBootTest
class KeyCloakConfigurationPropertiesBetaTest {
    @Autowired
    KeyCloakConfigurationProperties keyCloakConfigurationProperties;

    @Test
    void testProperty() {
        SoftAssertions.assertSoftly(softly -> {
            softly.assertThat(keyCloakConfigurationProperties.getUrl()).isEqualTo("https://test-keycloak.betatest.com");
            softly.assertThat(keyCloakConfigurationProperties.getUsername()).isEqualTo("honeymon-beta");
            softly.assertThat(keyCloakConfigurationProperties.getPassword()).isEqualTo("password-beta");
            softly.assertThat(keyCloakConfigurationProperties.getStoreMaps().get("DEFAULT_REALM")).isEqualTo("honeymon-beta");
        });
    }
}

////KeyCloakConfigurationPropertiesProdTest
@ActiveProfiles("prod")
@SpringBootTest
class KeyCloakConfigurationPropertiesProdTest {
    @Autowired
    KeyCloakConfigurationProperties keyCloakConfigurationProperties;

    @Test
    void testProperty() {
        SoftAssertions.assertSoftly(softly -> {
            softly.assertThat(keyCloakConfigurationProperties.getUrl()).isEqualTo("https://test-keycloak.test.com");
            softly.assertThat(keyCloakConfigurationProperties.getUsername()).isEqualTo("honeymon-prod");
            softly.assertThat(keyCloakConfigurationProperties.getPassword()).isEqualTo("password-prod");
            softly.assertThat(keyCloakConfigurationProperties.getStoreMaps().get("DEFAULT_REALM")).isEqualTo("honeymon-prod");
        });
    }
}

요런 식으로 해서 애플리케이션 구성파일을 작성하고 @ConfigurationProperties 빈을 작성하여 애플리케이션 구성파일 데이터를 활용할 수 있습니다.

"느슨한 연결(Relaxed Binding)"을 지원하기 때문에 다음과 같이 표현해도 스프링 부트가 SnakeYaml 로 읽어온 속성과 @ConfigurationProperties 빈의 필드를 매핑하여 주입합니다.

application-keycloak.yml`
keycloak:
  url: "https://test-keycloak.localtest.com"
  username: "honeymon-local"
  password: "password-local"
  store-maps: // 요렇게 해도!
    "DEFAULT_REALM": "honeymon-local"
    "DEFAULT_TOPIC": "topic"
---
keycloak:
  url: "https://test-keycloak.localtest.com"
  username: "honeymon-local"
  password: "password-local"
  storeMaps: // 요렇게 해도!
    "DEFAULT_REALM": "honeymon-local"
    "DEFAULT_TOPIC": "topic"

@ConfigurationProperties 빈 활용방법

앞서 작성한 KeyCloakConfigurationProperties 를 스프링 애플리케이션 컨텍스트에 적재하는 방법은 다음과 같습니다.

@Configuration
@EnableConfigurationProperties({KeyCloakConfigurationProperties.class}) // (1)
public class AppConfiguration {}

@Configuration
@ConfigurationPropertiesScan // (2)
public class AppConfiguration {}

@Component // (3)
@ConfigurationProperties("keycloak")
public class KeyCloakConfigurationProperties {
    // 코드 생략
}
  1. 활성화할 ConfigurationProperties 클래스를 명시적으로 지정하는 방법

  2. @ComponentScan 과 유사한 방식으로 @ConfigurationProperties 를 탐색하여 적재하는 방법

  3. @Component 애노테이션을 선언하여 컴포넌트 빈으로 적재하도록 하는 방법

의존성 주입방식

의존성 주입방식은 크게 3가지 방식이 있습니다.

  • @Autowired 선언 필드 주입방식

  • 설정자(setter 메서드) 주입방식

  • 생성자 주입방식

위 3가지 방법중에는 "생성자 주입방식"를 가장 높게 평가합니다. "`@Autowired` 선언 필드 주입방식" 은 권장하지 않습니다. 테스트 코드에서도 이런 방식으로 변경할 수 있습니다. 설정자 방식은 누락할 수 있다는 단점이 있습니다.

@ActiveProfiles("prod")
@SpringBootTest
class KeyCloakConfigurationPropertiesProdTest {
    @Autowired KeyCloakConfigurationProperties keyCloakConfigurationProperties; // @Autowired 필드 주입
}

@ActiveProfiles("prod")
@SpringBootTest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) // 테스트에서 조차....
class KeyCloakConfigurationPropertiesProdTest {
    private final KeyCloakConfigurationProperties keyCloakConfigurationProperties;

    public KeyCloakConfigurationPropertiesProdTest(KeyCloakConfigurationProperties keyCloakConfigurationProperties) {
        this.keyCloakConfigurationProperties = keyCloakConfigurationProperties;
    }
}

@ConfigurationProperties 주입

기존에 @Value 애노테이션을 이용해서 Environment 에 등록된 값을 주입하던 방식도 다음과 같이 ConfigurationProperties 빈을 주입하여 사용할 수 있다.

@Service
public class SomeService {
    @Value("${keycloak.username}")
    private String username;
    @Value("${keycloak.password}")
    private String password;

    public void print() {
        System.out.println(username);
        System.out.println(password);
    }
}

적재된 @ConfigurationProperties 빈은 일반 스프링 빈과 동일하게 "의존성 주입(Dependency Injection)"을 활용할 수 있습니다.

@Service
public class SomeService {
    private final KeyCloakConfigurationProperties keyCloakConfigurationProperties;

    public SomeService(KeyCloakConfigurationProperties keyCloakConfigurationProperties) { // 생성자 주입방식 활용
        this.keyCloakConfigurationProperties = keyCloakConfigurationProperties;
    }

    public void print() {
        System.out.println(keyCloakConfigurationProperties.getUsername());
        System.out.println(keyCloakConfigurationProperties.getPassword());
    }
}
@Y-k-Y
Copy link

Y-k-Y commented Nov 4, 2022

좋은 자료 감사합니다🙇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment