Spring

@Profile과 @ActiveProfile

윤밥밥 2025. 2. 20. 13:58

@Profile과 @ActiveProfile

application.properties or yml에서 어떤 프로필을 사용할 지 결정할 수 있다.

spring.profiles.active=dev,local 이라고 명시하면 dev 프로필과 local 프로필을 사용하게 된다.

반면 Spring 코드 내에서 운영 환경에 따라 다른 빈을 주입해야 할 수도 있다.

메인 환경에서는 RedisMainConfig를 개발환경에서는 RedisDevConfig를 사용해 서로 다른 캐시를 사용해야 할 수도 있다.

또한 테스트 환경에서는 특정 프로필과 다른 프로필을 사용해야 할 수있다.

이럴 경우 @Profile 혹은 @ActiveProfile을 사용할 수 있다.

1. @Profile

@Profile은 환경에 따라 Bean의 로딩을 다르게 할 수 있는 기능이다.

사용법 1. 클래스 위에 붙인다.

@Configuration 이 붙은 클래스나 @Component, @Service, @Repository 등이 붙은 클래스 위에 붙일 수 있다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev") // dev 환경에서만 적용
public class DevConfig {

    @Bean
    public DataSource dataSource() {
        return new DataSource("jdbc:mysql://localhost:3306/dev_db");
    }
}

위처럼 Config 파일 위에 명시하면 위 Config클래스는 dev 프로필일 경우에만 등록된다.

사용법 2. 메서드에 붙인다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
public class DataSourceConfig {

    @Bean
    @Profile("dev") // "dev" 환경에서만 활성화
    public DataSource devDataSource() {
        return new DataSource("jdbc:mysql://localhost:3306/dev_db", "dev_user", "dev_password");
    }

    @Bean
    @Profile("prod") // "prod" 환경에서만 활성화
    public DataSource prodDataSource() {
        return new DataSource("jdbc:mysql://prod-db-url:3306/prod_db", "prod_user", "prod_password");
    }
}

위와 같이 Configuration 파일 안에 메서드에 @Profile 을 붙여 사용할 수도 있다.

팁 1. 여러 프로필을 적용

참고로 {}를 활용해 여러 프로필을 적용할 수도 있다.

@Profile({"dev", "test"}) 이는 dev or test 환경에서 활성화된다.

팁 2. 특정 프로필 제외

!을 사용해서 특정 프로필을 제외하고 모든 환경에서 활성화할 수도 있다.

@Profile("!dev") 이는 dev환경 외에서 모두 활성화한다.

참고로 JpaRepository를 사용한 인터페이스에는 적용할 수 없다.

JpaRepository를 사용한 인터페이스에는 적용할 수 없다. JpaRepository를 상속한 인터페이스는 아래와 같이 애노테이션을 붙여도 작동하지 않는다.

@Profile("dev")
public interface MemberRepository extends JpaRepository<Member, Long> {
    Optional<Member> findByEmail(String email);
    boolean existsByEmail(String email);
}

JpaRepository를 구현한 인터페이스에 대해서는 Spring Data JPA가 실제 구현체를 만들어줘서 프록시로 등록해 사용한다.

이 때 인터페이스가 아니라, 프록시를 사용하기 때문에 @Profile 애노테이션은 구현체에 붙지 않는다.

그래서 만약 @Profile 애노테이션을 붙이고 싶으면 직접 Repository를 구현해야 한다.

2. @ActiveProfiles

@ActiveProfiles란 테스트 환경에서 어떤 프로필을 사용할 지 결정하는 애노테이션이다. 즉 별도로 spring.profiles.active = test 지정하지 않아도 테스트에서 특정 프로필을 적용할 수 있다.

@SpringBootTest
@ActiveProfiles("test") // 테스트 실행 시 "test" 프로파일 활성화
public class DataSourceTest {

    @Test
    void testDataSource() {
        // 테스트 코드 실행 시 "test" 프로파일이 적용됨
    }
}

3. @Profile의 동작과정

Spring은 초기 실행될 때 현재 활성화된 프로필 목록을 내부적으로 저장해둔다.

이 후 빈을 스캔하여 등록할 때 @Profile 확인하여 설정된 빈과 일치하는 지 체크한다. 만약 맞지 않으면 빈을 제외한다.