지난 포스팅에서 설정을 객체로 정의하면 구조와 의도가 코드에 자연스럽게 드러난다는 점은 확인했습니다. 하지만, 한 가지 질문이 남습니다.

@ConfigurationProperties로 선언한 설정 클래스는 언제, 어떻게 Spring Bean(이하, “Bean”)으로 등록되는 걸까요?

이 지점에서 등장하는 것이 @EnableConfigurationProperties 어노테이션입니다.


1. 설정을 활성화하는 방법, @EnableConfigurationProperties

@ConfigurationProperties는 설정값을 객체에 바인딩하는 역할을 합니다. 반면 @EnableConfigurationProperties는 해당 설정 객체를 Bean으로 등록할 수 있도록 합니다.

@Configuration
@EnableConfigurationProperties(ExternalApiProperties.class)
public class ExternalApiConfig {
}

설정 객체가 Bean으로 등록되면 다른 컴포넌트에서 주입받아 사용할 수 있습니다.

@Component
@RequiredArgsConstructor
public class ExternalApiClient {

    private final ExternalApiProperties properties;

    public void call() {
        String url = properties.getUrl(); // https://example.com
        int timeout = properties.getTimeout(); // 3000
        // ...
    }
}

@Component
@RequiredArgsConstructor
public class ExternalApiRetryPolicy {

    private final ExternalApiProperties properties;

    public int retryCount() {
        return properties.getRetry(); // 3
    }
}

2. @Component와 @EnableConfigurationProperties의 차이

그렇다면 이런 질문이 자연스럽게 떠오릅니다.

@EnableConfigurationProperties를 사용하지 않고, 그냥 @Component를 사용하면 되는 것 아닐까?

실제로 다음과 같이 코드를 작성하는 것도 가능합니다.

@Component
@ConfigurationProperties(prefix = "external.api")
public class ExternalApiProperties {

    private String url;
    private int timeout;
    private int retry;

    // getter / setter
}

이렇게 하면 ExternalApiProperties는 컴포넌트 스캔 대상이 되어 자동으로 Spring 컨텍스트에 Bean으로 등록됩니다.

그렇다면 굳이 @EnableConfigurationProperties 어노테이션을 사용할 필요가 있을까요? 두 방식의 차이점을 정리해보면 다음과 같습니다.

구분 @Component @EnableConfigurationProperties
등록 방식 자동 컴포넌트 스캔 명시적 등록
용도 일반 컴포넌트 설정 객체 등록
라이브러리/모듈화 적합하지 않음 적합
구조적 명확성 비교적 낮음 높음

@Component를 사용하는 방식이 분명 빠르고 간편해 보입니다. 하지만, 설정 클래스가 많아질수록 설정 객체와 일반 컴포넌트를 구분하기 어려워질 수 있습니다.

반면 @EnableConfigurationProperties를 사용하면 설정은 “구성 단계에서 활성화되는 요소”라는 인식이 더 분명해질 수 있습니다.

@Component를 사용해도 설정 객체가 Bean으로 등록이 되지만, 설정을 위한 별도의 구성 의도를 드러내지 못할 수 있습니다. 일반적인 애플리케이션이라면 @Component를 사용해도 큰 문제는 없습니다. 하지만 설정의 역할을 명확히 구분하거나 라이브러리 형태로 제공한다면 @EnableConfigurationProperties를 사용하는 것이 더 적합합니다.


3. 설정에 따라 동작을 제어하는 방법, @ConditionalOnProperty

때로는 특정 설정 값에 따라 애플리케이션의 동작을 수행하는 코드를 분기 처리해야 할 필요가 있습니다.

  • 특정 기능의 ON/OFF
  • 캐시 기능 활성화 여부
  • 외부 API 연동 기능 활성화 여부

이때, @ConditionalOnProperty를 사용할 수 있습니다. @ConditionalOnProperty는 특정 설정값의 존재 여부나 값에 따라 Bean 등록 여부를 결정하는 어노테이션입니다.

지금까지 사용한 application.yml 파일에 enabled라는 설정을 추가해보겠습니다.

external:
  api:
    url: https://example.com
    timeout: 3000
    retry: 3
    enabled: true

아래처럼 @ConditionalOnProperty으로 선언하면 external.api.enabled의 값이 true인 경우에만 ExternalApiClient가 Bean으로 등록됩니다.

@Component
@RequiredArgsConstructor
@ConditionalOnProperty(
        prefix = "external.api",    // 설정 키의 공통 접두사
        name = "enabled",           // 확인할 설정 이름
        havingValue = "true",       // true일 때만 Bean 등록
        matchIfMissing = false)     // 설정이 없으면 Bean 등록하지 않음
public class ExternalApiClient {

    private final ExternalApiProperties properties; 
    
    public void call() { 
        String url = properties.getUrl();       // https://example.com 
        int timeout = properties.getTimeout();  // 3000 
        // ... 
    }
}

반대로 external.api.enabled의 값이 false이거나, 설정이 존재하지 않으면 ExternalApiClient는 Bean으로 등록되지 않습니다. 즉, @ConditionalOnProperty를 사용하면 단순히 설정값을 전달하는 역할을 넘어 애플리케이션의 구성과 기능 활성화 여부까지 제어할 수 있습니다.


4. 마무리

@ConfigurationProperties는 설정을 객체로 관리하기 위한 기능이고, @EnableConfigurationProperties는 설정 객체를 Bean으로 등록하기 위한 기능입니다.

그리고 @ConditionalOnProperty를 함께 사용하면 설정값에 따라 Bean 등록 여부를 제어할 수 있습니다.

이처럼 Spring에서는 설정을 단순한 값이 아니라, 애플리케이션의 구성과 동작을 제어하는 요소로 활용할 수 있습니다.