[Spring] 실무에서 @ConditionalOnProperty를 사용하는법

HenryHong·2026년 1월 20일

Spring

목록 보기
1/4
post-thumbnail

스프링 부트로 서비스 운영하다 보면 “이 기능은 운영에서만 켜자”, “로컬에선 Mock만 쓰자” 같은 요구가 계속 생긴다. 이런 요구를 깔끔하게 처리하는 핵심 도구 중 하나가 바로 @ConditionalOnProperty다.


1. @ConditionalOnProperty가 하는 일

@ConditionalOnProperty는 설정 파일에 정의된 프로퍼티 값을 보고, 조건이 맞을 때만 빈을 등록한다.

@ConditionalOnProperty(
    name = "feature.enabled",
    havingValue = "true"
)
  • feature.enabled=true → 빈 등록
  • 그 외 값 / 미설정 → 빈 미등록

정리하면, “환경 설정 값에 따라 기능을 켜고 끄는 스위치 역할”을 하는 어노테이션이다.


2. 가장 기본적인 사용법

예시로, feature-x라는 기능을 설정으로 제어하는 케이스를 보자.

# application.yml
myapp:
  feature-x:
    enabled: true
@Configuration
public class FeatureXConfig {

    @Bean
    @ConditionalOnProperty(
        name = "myapp.feature-x.enabled",
        havingValue = "true",
        matchIfMissing = false
    )
    public FeatureXService featureXService() {
        return new FeatureXService();
    }
}

핵심 파라미터만 짚고 넘어간다.

  • name: 검사할 프로퍼티 이름
  • havingValue: 이 값과 문자열로 일치할 때 조건 만족
  • matchIfMissing: 프로퍼티가 아예 없을 때도 조건을 만족시키고 싶다면 true, 기본은 false

이 설정에서는 myapp.feature-x.enabled=true일 때만 FeatureXService가 빈으로 올라온다.


3. 구현 스위치: Redis vs RDB

같은 인터페이스에 여러 구현을 두고, 설정 값으로 구현을 고르는 패턴이다.

public interface SessionStore {
    String get(String key);
}
@Service
@ConditionalOnProperty(
    name = "session.store",
    havingValue = "redis"
)
class RedisSessionStore implements SessionStore {
    @Override
    public String get(String key) {
        // Redis 조회 로직
        return "...";
    }
}
@Service
@ConditionalOnProperty(
    name = "session.store",
    havingValue = "rdb",
    matchIfMissing = true
)
class JdbcSessionStore implements SessionStore {
    @Override
    public String get(String key) {
        // RDB 조회 로직
        return "...";
    }
}
# application.yml
session:
  store: redis   # redis / rdb

session.store 값만 바꿔도 세션 저장소 구현이 교체된다.
로컬·테스트에서는 rdb, 운영에서는 redis 같은 식으로 환경별 전략을 설정으로 분리할 수 있다.


4. 로컬 전용 Mock 빈 구성

외부 결제, 외부 API 호출처럼 실제로는 운영에서만 붙어야 하는 영역에 특히 유용하다.

# application-local.yml
myapp:
  payment:
    mock-mode: true
public interface PaymentClient {
    void pay();
}
@Service
@ConditionalOnProperty(
    name = "myapp.payment.mock-mode",
    havingValue = "true"
)
class MockPaymentClient implements PaymentClient {
    @Override
    public void pay() {
        System.out.println("Mock payment invoked");
    }
}
@Service
@ConditionalOnProperty(
    name = "myapp.payment.mock-mode",
    havingValue = "false",
    matchIfMissing = true
)
class RealPaymentClient implements PaymentClient {
    @Override
    public void pay() {
        // 실제 결제 API 호출
    }
}

로컬 프로파일에서 mock-mode=true를, 운영에서는 false 또는 미설정을 두면, 코드 수정 없이 환경별로 Mock / Real 구현이 갈린다.


5. Profile과의 차이, 그리고 다른 조건부 어노테이션들

@Profile@ConditionalOnProperty는 목적이 미묘하게 다르다.

  • @Profile("local")
    • 로컬 / dev / prod 같은 환경 단위 나누기
  • @ConditionalOnProperty(name = "...", havingValue = "...")
    • 같은 환경 안에서도, 기능 단위로 세밀하게 토글할 때 사용

같은 계열로 묶어볼 수 있는 조건부 어노테이션들도 있다.

  • @ConditionalOnClass / @ConditionalOnMissingClass
    • 특정 라이브러리가 클래스패스에 있는지 여부로 결정
  • @ConditionalOnBean / @ConditionalOnMissingBean
    • 다른 빈 존재 여부에 따라 설정 분기
      @ConditionalOnProperty는 이 중에서 “환경 설정 파일 기반 기능 스위치” 포지션이라고 보면 된다.

6. 마무리

@ConditionalOnProperty 한 번 익혀 두면 “이 기능은 운영에서만 쓰자”, “이 구현은 당분간 꺼 두자” 같은 요구를 전부 설정 레벨로 끌어올릴 수 있다. 실제 코드 분기는 어노테이션과 프로퍼티 값이 책임지고, 개발자는 설정만 바꿔서 실험·롤백·A/B 테스트까지 처리하는 구조를 가져갈 수 있다.

profile
주니어 백엔드 개발자

0개의 댓글