본문 바로가기

Spring Framework/Spring Boot

[Spring Boot] 커스텀 프로퍼티 완벽 가이드

개요

Spring Boot 개발을 하다 보면 하드코딩된 값들로 인해 고민을 하게 된다.

"이 설정값을 바꾸려면 또 코드를 수정하고 배포해야 하나?" 라는 생각이 들 때가 종종 생긴다.

 

이런 문제를 해결해주는 것이 바로 커스텀 프로퍼티이다.

이 글에서 커스텀 프로퍼티가 무엇인지, 어떻게 사용하는지, 그리고 언제 사용해야 하는지에 대해 자세히 알아보자.

 

 

 

1. 커스텀 프로퍼티란?

커스텀 프로퍼티는 애플리케이션에서 필요한 설정값들을 application.properties 또는 application.yml 파일에 정의하고, 이를 Java 코드에서 사용할 수 있도록 하는 Spring Boot의 기능이다.

 

간단한 예시로 시작해보자:

# application.properties
spring.application.name=demo

# 커스텀 프로퍼티
myapp.name=데모 애플리케이션
myapp.version=1.0.0
myapp.admin.email=admin@example.com
myapp.database.max-connections=10
myapp.features.email-enabled=true

 

 

 

2. 커스텀 프로퍼티 사용법

1. @Value 어노테이션 사용 - 서비스에서 직접 사용

가장 간단한 방법이다:

@Component
public class MyService {
    
    @Value("${myapp.name}")
    private String appName;
    
    @Value("${myapp.admin.email}")
    private String adminEmail;
    
    @Value("${myapp.database.max-connections:5}") // 기본값 5
    private int maxConnections;
    
    public void printConfig() {
        System.out.println("앱 이름: " + appName);
        System.out.println("관리자 이메일: " + adminEmail);
        System.out.println("최대 연결수: " + maxConnections);
    }
}

 

2. @ConfigurationProperties 사용 - 프로퍼티 클래스로 사용

더 체계적이고 안전한 방법이다:

@ConfigurationProperties(prefix = "myapp")
@RequiredArgsConstructor
@Getter
public class AppProperties {
    
    private final String name;
    private final String version;
    private final Admin admin;
    private final Database database;
    private final Features features;
    
    @RequiredArgsConstructor
    @Getter
    public static class Admin {
        private final String email;
    }
    
    @RequiredArgsConstructor
    @Getter
    public static class Database {
        private final int maxConnections;
    }
    
    @RequiredArgsConstructor
    @Getter
    public static class Features {
        private final boolean emailEnabled;
    }
}

 

실제 사용

@RestController
@RequiredArgsConstructor
public class ConfigController {
    
    private final AppProperties appProperties;
    
    @GetMapping("/config")
    public String getConfig() {
        return String.format(
            "앱: %s (버전: %s), 관리자: %s, 최대 연결: %d, 이메일 활성화: %s",
            appProperties.getName(),
            appProperties.getVersion(),
            appProperties.getAdmin().getEmail(),
            appProperties.getDatabase().getMaxConnections(),
            appProperties.getFeatures().isEmailEnabled()
        );
    }
}

 

 

 

3. 프로퍼티 클래스 등록 방법

Spring Boot 2.6+ 버전에서는 단일 생성자가 있으면 @ConstructorBinding을 생략할 수 있다.

그리고 프로퍼티 클래스를 등록하는 방법도 여러 가지가 있다.

 

방법 1: @ConfigurationPropertiesScan (전체 스캔)

@SpringBootApplication
@ConfigurationPropertiesScan  // 패키지 전체를 스캔해서 자동 등록
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

 

방법 2: @EnableConfigurationProperites (개별 지정)

@SpringBootApplication
@EnableConfigurationProperties({AppProperties.class, DatabaseProperties.class})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

 

방법 3: @Component (컴포넌트로 등록)

@ConfigurationProperties(prefix = "myapp")
@RequiredArgsConstructor
@Getter
@Component  // 이렇게 하면 메인 클래스에 아무것도 안해도 됨
public class AppProperties {
    private final String name;
    private final String version;
}

 

방법 4: @Configuration에서 @Bean 등록

@Configuration
public class PropertiesConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "myapp")
    public AppProperties appProperties() {
        return new AppProperties();
    }
}

 

등록 방법별 장단점과 권장사항

방법 장점 단점
@ConfigurationPropertiesScan 자동으로 모든 프로퍼티 클래스 등록 어떤 클래스가 등록되는지 파악하기 어려움
@EnableConfigurationProperties 명시적이고 관리하기 쉬움 새 프로퍼티 클래스마다 추가 필요
@Component 가장 간단함 프로퍼티 클래스가 일반 컴포넌트와 섞임
@Bean 등록 세밀한 제어 가능 코드가 복잡해짐

 

소규모 프로젝트라면 간단하게 @Component를,

대규모 프로젝트라면 @EnableConfigurationProperties로 명시적으로 관리를,

프로퍼티 클래스가 많다면 @ConfigurationPropertiesScan으로 간편하게 등록하면 좋을 거 같다.

 

 

 

4. 환경별 설정

기본 속성값들도 환경별로 설정이 다르듯이 커스텀 프로퍼티도 환경별로 다른 설정값이 필요하다.

 

  • application.properties (기본 설정)
  • application-dev.properties (개발환경)
  • application-prod.properties (운영환경)
# application-dev.properties
myapp.database.max-connections=5
myapp.admin.email=dev-admin@example.com

# application-prod.properties
myapp.database.max-connections=50
myapp.admin.email=prod-admin@company.com

 

 

 

5. final 변수와 차이점

근데 커스텀 프로퍼티의 용도를 보다보면 final 변수와 같지 않나? 라는 생각이 든다.

그래서 관련 정보를 찾아보았다.

 

final 변수 (하드코딩)

public class EmailService {
    private final String smtpServer = "smtp.gmail.com";  // 컴파일 타임에 고정
    private final int port = 587;
}

 

커스텀 프로퍼티 (외부 설정)

@ConfigurationProperties(prefix = "email")
@RequiredArgsConstructor
@Getter
public class EmailProperties {
    private final String smtpServer;  // 런타임에 외부에서 주입
    private final int port;
}

 

핵심 차이점

구분 final 변수 커스텀 프로퍼티
값 결정 시점 컴파일 타임 런타임
설정 변경 코드 수정 + 재컴파일 필요 설정 파일만 수정
환경별 설정 불가능 가능
외부 주입 불가능 가능
Docker 환경 새 이미지 빌드 필요 환경변수로 변경 가능

 

실제 예시

# final 변수는 이런 게 안됨
java -jar app.jar --app-name="새로운이름"

# 커스텀 프로퍼티는 실행 시점에 값 변경 가능
java -jar app.jar --myapp.name="새로운이름"

 

 

 

결론

커스텀 프로퍼티는 단순히 설정값을 외부로 빼내는 것 이상의 의미가 있다:

  • 유연성: 재배포 없이 설정 변경 가능
  • 환경 분리: 개발/운영 환경별 설정 관리
  • 안전성: 타입 안전한 설정 바인딩
  • 유지보수성: 중앙집중식 설정 관리

하지만 모든 상수를 커스텀 프로퍼티로 만들 필요는 없다. 변경 가능성비즈니스 관련성을 기준으로 적절히 판단하여 사용하자.