개요
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="새로운이름"
결론
커스텀 프로퍼티는 단순히 설정값을 외부로 빼내는 것 이상의 의미가 있다:
- 유연성: 재배포 없이 설정 변경 가능
- 환경 분리: 개발/운영 환경별 설정 관리
- 안전성: 타입 안전한 설정 바인딩
- 유지보수성: 중앙집중식 설정 관리
하지만 모든 상수를 커스텀 프로퍼티로 만들 필요는 없다. 변경 가능성과 비즈니스 관련성을 기준으로 적절히 판단하여 사용하자.
'Spring Framework > Spring Boot' 카테고리의 다른 글
| [Spring Boot] 환경별 설정 어떻게 해야할까? (2) | 2025.07.28 |
|---|---|
| [Spring Boot] 스프링 부트 이벤트 리스너 구현과 등록 (2) | 2025.07.17 |
| [Spring Boot] SpringApplication.run() 메서드 인자에 관해서 (0) | 2025.07.17 |
| [Spring Boot] 리액티브 프로그래밍이란? (0) | 2025.07.17 |
| [Spring Boot] 스프링 부트 애플리케이션 종료 (1) | 2025.07.02 |