YAML (Yet Another Markup Language) 이란?

풀어갈 나의 이야기·2025년 4월 2일
0

Spring Framework

목록 보기
5/5
post-thumbnail

📌 YAML (Yet Another Markup Language) 이란?

  • YAML사람이 읽기 쉬운 데이터 포맷
  • 주로 설정 파일, 데이터 직렬화 등으로 사용되며, JSON보다 가독성이 뛰어남

🔎 특징

  • 들여쓰기로 계층 표현
  • 주석 가능 (#)
  • 리스트와 맵 표현이 간결함

🔎 예시

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: secret

🔎 YAML 의 기본 구조 및 특징

✏️ 가독성

  • JSON
{
  "name": "John Doe",
  "age": 30,
  "isEmployee": true
}
  • yaml
name: John Doe
age: 30
isEmployee: true

✏️ 데이터 구조

  • 스칼라 : 문자열, 숫자, 불리언 (참/거짓) 값과 같은 기본 데이터 타입

    • age: 30은 정수 스칼라
  • 리스트 : 배열이나 목록을 표현

    • 각 항목은 동일한 들여쓰기 레벨에서 하이픈 (-)으로 시작

      hobbies:
        - Reading
        - Hiking
        - Coding
  • 맵 : 키-값 쌍으로 데이터를 구성

    • 객체나 레코드를 표현하는 데 유용

      address:
        street: 123 Main St
        city: Anytown
        zip: 12345

✏️ 앵커와 별칭 사용

  • YAML에서는 앵커(&)와 별칭(*)을 사용하여 데이터를 재사용
# 앵커
defaultAddress: &address
  street: 123 Main St
  city: Anytown
  zip: 12345

# 앵커참조
johnsAddress: *address
janesAddress:
  <<: *address
  street: 456 Elm St

✏️ 줄바꿈

  • 리터럴 스타일 (Literal Style): | 기호를 사용
    • 줄바꿈을 유지하며, 문자열을 그대로 보존
| 
  여러 줄의
  텍스트를
  그대로 보존합니다.
  • 폴디드 스타일 (Folded Style): > 기호를 사용
> 
  이것은 하나의
  긴 문장입니다.
  이 줄바꿈은 유지됩니다.

  새로운 단락입니다.

📌 YAML Loader란?

🔎 YAML Loader의 역할

  • .yml 파일을 Java 객체(Map, List, POJO 등) 로 변환
  • Spring Boot는 YamlPropertySourceLoader를 통해 application.ymlPropertySource로 등록
    • 이전에는 @PropertySource 를 통해 리소스를 불러왔지만, 이는 추천하는 방식이 아니라고 함

🔎 사용 예 (Java with SnakeYAML)

Yaml yaml = new Yaml();
InputStream input = new FileInputStream(new File("config.yml"));
Map<String, Object> data = yaml.load(input);

📌 Spring Boot에서 YAML이 바인딩되는 과정

🔎 application.yml → Java 객체로 주입되는 원리

Spring Boot는 어떻게 application.yml 내용을 Java 객체에 주입할까?

  • @SpringBootApplication이 하는 일

    • @SpringBootConfiguration // @Configuration 포함 - 설정 클래스 선언
    • @EnableAutoConfiguration // classpath에 있는 설정 기반으로 자동 설정
    • @ComponentScan // 현재 패키지 이하의 Bean 자동 스캔
  • Spring Boot Application 실행 흐름

      1. main() → SpringApplication.run(App.class, args)
      1. SpringApplication 인스턴스 생성
        • ApplicationContext 초기화
        • Environment 객체 생성 및 Profile 설정
        • application.yml/.properties 로드
        • AutoConfiguration 후킹
        • @ComponentScan 수행
      1. Bean 등록 및 초기화
      1. CommandLineRunner 등 후처리기 실행

🔎 전반적인 동작 흐름

  1. Spring Boot 시작
    • SpringApplication 이 실행되면서 내부적으로 ConfigDataEnvironmentPostProcessor가 동작
      • application yml 을 읽는 구조
        • 내부적으로 사용하는 클래스
          • ConfigFileApplicationListener
            • → EnvironmentPostProcessor
            • → ConfigDataEnvironmentPostProcessor
  2. 설정 파일 탐색 및 로딩
    • application.yml 혹은 application.propertiesYamlPropertySourceLoader 등을 통해 파싱
    • 결과는 MapPropertySource 형태로 Environment에 등록
  3. 설정 값 바인딩
    • @ConfigurationProperties가 붙은 클래스를 ConfigurationPropertiesBindingPostProcessor가 감지
    • BinderEnvironment에서 prefix에 맞는 값을 찾아 해당 클래스 필드에 주입
  4. 타입 변환 처리
    • 내부적으로 ConversionService가 사용되어 문자열 값을 Java 타입으로 변환

Springboot 2.4.0 부터 application.properties 를 인식하는것이 부터 코드내에 변경되었다.

🔎 YAML → Java 객체 바인딩 흐름

Spring Boot에서 application.yml에 정의된 설정들이 Java 객체로 바인딩되는 전체 과정을 설명합니다.

✏️ SpringApplication.run(...) 호출

  • Spring Boot 실행 시작
  • 내부적으로 환경(Environment) 준비 단계로 진입

✏️ ConfigDataEnvironmentPostProcessor 실행

  • application.yml, application-{profile}.yml 등 설정 파일 로딩
  • YamlPropertySourceLoader.yml 파일을 Map<String, Object> 형태로 파싱

✏️ Environment 에 PropertySource 로 등록

  • 예: application.ymlapplicationConfig: [classpath:/application.yml]
  • 등록된 값은 Environment.getProperty("myapp.title") 방식으로 접근 가능

✏️ 바인딩 대상 클래스 탐색

  • @ConfigurationProperties(prefix = "myapp")
    또는 @Value("${myapp.title}") 같은 애노테이션이 붙은 클래스나 필드를 스캔

✏️ Binder 동작

  • Spring Boot의 org.springframework.boot.context.properties.bind.Binder 클래스가
    Environment의 값들을 Java Bean으로 바인딩

✏️ 타입 변환 (ConversionService)

  • 문자열로 되어있는 값들을 해당 필드의 타입에 맞게 자동 변환

예:

myapp:
  enabled: true
  max-users: 100
@ConfigurationProperties(prefix = "myapp")
public class MyAppConfig {
    private boolean enabled;    // 문자열 "true" → boolean
    private int maxUsers;       // 문자열 "100" → int
}

✏️ 객체 주입

  • 완성된 설정 객체는 @Component, @EnableConfigurationProperties,
    또는 @Bean 등록 등을 통해 스프링 컨테이너에 등록되어 사용 가능

✏️ 전체 흐름 요약

@startuml
title YAML → Java 객체 바인딩 흐름

actor "개발자" as Dev
participant "application.yml" as YML
participant "YamlPropertySourceLoader" as Loader
participant "Map<String, Object>" as MapData
participant "Environment\n(PropertySources)" as Env
participant "@ConfigurationProperties\nor @Value" as Annotation
participant "Binder" as Binder
participant "ConversionService" as Converter
participant "Java 객체 (POJO)" as POJO

Dev -> YML : 설정 작성
YML -> Loader : YML 파일 로딩 요청
Loader -> MapData : YAML → Map 변환
MapData -> Env : PropertySource 로 등록
Env -> Annotation : @ConfigurationProperties 로 매핑 대상 감지
Annotation -> Binder : prefix 기준 바인딩 요청
Binder -> Env : 설정 값 조회
Binder -> Converter : 타입 변환 요청
Converter -> POJO : 최종 타입 객체 생성

@enduml
application.yml
     ↓
YamlPropertySourceLoader
     ↓
Map<String, Object>
     ↓
Environment (PropertySources)
     ↓
@ConfigurationProperties / @Value
     ↓
Binder
     ↓
ConversionService (타입 변환)
     ↓
Java 객체 (POJO)

✏️ 예시

  • application.yml
myapp:
  title: Hello YAML
  port: 8081
  enabled: true
  • Java 객체
@Component
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
    private String title;
    private int port;
    private boolean enabled;

    // Getters / Setters
}

🔎 핵심 클래스

구성 요소역할
YamlPropertySourceLoaderYAML 파일을 읽고 파싱
Environment설정 값 저장소 역할
BinderYAML → Java 객체로 바인딩 수행
ConfigurationPropertiesBindingPostProcessor바인딩 트리거 역할
ConversionService문자열 → 실제 타입으로 변환

🔎 핵심 메커니즘

  1. SpringApplication 실행
  2. YamlPropertySourceLoaderapplication.yml을 파싱
  3. 결과를 Environment에 등록 (PropertySource)
  4. @ConfigurationProperties, @Value, Environment.getProperty() 등으로 값 주입

🔎 예시

application.yml

myapp:
  title: "Welcome Application"

ConfigurationProperties

@Component
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
    private String title;
    // Getter / Setter
}

📌 다양한 PropertySource 종류와 우선순위

Spring Boot는 다양한 설정 소스를 읽고 이를 Environment에 등록한다.
우선순위가 높을수록 설정이 override 됨

우선순위 정리 (높음 → 낮음)

우선순위종류설명
1CommandLinePropertySource--key=value 형식으로 실행 시 전달한 값
2SystemEnvironmentPropertySource시스템 환경변수 (MYAPP_TITLE=...)
3SystemPropertiesPropertySourceJVM 옵션 (-Dmyapp.title=...)
4RandomValuePropertySource${random.uuid} 등 지원
5application-{profile}.yml활성화된 프로파일 전용 설정
6application.yml기본 설정 파일
7@PropertySource자바 클래스에서 명시한 .properties 파일
8setDefaultProperties()Java 코드에서 기본 설정 지정

📌 PropertySource 우선순위 실험 예제

🔎 설정 위치별 설정 예

application.properties

myapp.title=Application Default Title

application-dev.properties

myapp.title=Application Dev Profile Title

DemoApplication.java

public static void main(String[] args) {
    SpringApplication app = new SpringApplication(DemoApplication.class);
    Map<String, Object> defaults = Map.of("myapp.title", "Fallback Default Title");
    app.setDefaultProperties(defaults);
    app.run(args);
}

실행 시 명령줄 인자

java -jar app.jar --spring.profiles.active=dev --myapp.title=Command Line Title

컨트롤러에서 출력

@RestController
public class TitleController {
    @Value("${myapp.title}")
    private String title;

    @GetMapping("/title")
    public String title() {
        return title;
    }
}

🔎 출력 결과 (실행 옵션에 따라)

실행 상황결과값
기본 실행Application Default Title
-Dspring.profiles.active=devApplication Dev Profile Title
명령줄 인자 추가Command Line Title
아무것도 없을 때Fallback Default Title

정리

  • Spring Boot는 다양한 소스로부터 설정을 로딩하고, 우선순위에 따라 값을 결정함
  • @ConfigurationProperties는 타입 안정성과 계층적 매핑을 제공함
  • YamlPropertySourceLoaderapplication.ymlPropertySource로 만들어 환경 설정에 반영함
  • 우선순위 실험을 통해 어떤 설정이 실제 적용되는지 확인 가능

📌 YamlPropertySourceLoader 분석

Spring Boot에서 application.yml 파일을 읽어 환경 설정으로 등록해주는 핵심 컴포넌트


🔎 YamlPropertySourceLoader의 핵심 역할

public class YamlPropertySourceLoader implements PropertySourceLoader {
    @Override
    public String[] getFileExtensions() {
        return new String[] { "yml", "yaml" };
    }

    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        ...
        return result;
    }
}

.yml, .yaml 확장자를 가진 리소스를 읽어 PropertySource 객체로 반환

🔎 Spring Boot 실행 시 전체 동작 흐름

  1. SpringApplication.run(...)
  2. ConfigDataEnvironmentPostProcessor 실행
  3. .yml 파일이면 YamlConfigDataLoaderYamlPropertySourceLoader 호출
  4. OriginTrackedYamlLoader.load()Map<String, Object>
  5. OriginTrackedMapPropertySource 로 wrapping 후 Environment에 등록
    • 이걸 Spring이 이해할 수 있게 PropertySource로 wrapping
    • PropertySource는 Environment에 등록되는 객체 타입

위 과정을 거치면 Spring Boot 안 어디에서든지 아래처럼 접근 가능

@Value("${server.port}") // 8080

혹은 
environment.getProperty("spring.profiles.active");

🔎 추가팁

  • .properties 파일은 PropertiesPropertySourceLoader가 처리
  • Spring Boot 2.4 이전에는 ConfigFileApplicationListener가 설정 파일을 로딩했음
  • spring.factories 또는 META-INF/spring/ 경로를 통해 자동 등록됨
profile
깨끗한 스케치북 일수록 우아한 그림이 그려지법, 읽기 쉽고, 짧은 코드가 더 아름다운 법, 개발이란 구현할 프로그래밍이 아닌 풀어갈 이야기로 써내려가는것.

0개의 댓글

관련 채용 정보