- 프로필(Profile)은 스프링 프레임워크의 핵심 기능으로, 사용자가 정의한 빈을 서로 다른 프로필(예를 들어, dev, test, prod)에 매핑할 수 있도록 한다.
- 그런 다음 서로 다른 환경에서 서로 다른 프로필을 활성화하여 필요한 빈만 부트스트랩할 수 있도록 지원한다.
- 간단하게 특정 프로필에 속하는 빈을 만드는 방법에 대해 알아보자. @Profile 주석을 사용하여 특정 프로필에 빈을 매핑할 것이다. 어노테이션은 단순히 하나(또는 여러) 프로필의 이름을 사용할 수 있다.
- 개발 중에는 활성화되어야 하지만 프로덕션에는 배포되지 않아야 하는 빈이 있다고 하자.
- 해당 Bean에 dev 프로필 주석을 달면 개발 환경에서만 컨테이너에 표시되게 할 수 있다. 즉, dev 프로필은 프로덕션에서 활성화되지 않습는다.
@Component @Profile("dev") public class DevDatasourceConfig
- 참고로 프로필 이름 앞에 NOT 연산자를 추가할 수도 있다(예: !dev).
@Component @Profile("!dev") public class DevDatasourceConfig
- 프로필은 XML로 구성할 수도 있다.
<beans>
태그 안에 해당하는 프로필 속성을 포함하면 된다.<beans profile="dev"> <bean id="devDatasourceConfig" class="org.baeldung.profiles.DevDatasourceConfig" /> </beans>
- 다음 단계는 해당 Bean이 컨테이너에 등록되도록 프로필을 활성화하고 설정하는 것이다. 이를 수행하는 방법은 여러 가지다.
- 먼저 웹 애플리케이션에서 WebApplicationInitializer를 사용하여 프로그래밍 방식으로 ServletContext를 구성할 수 있다.
- WebApplicationInitializer는 활성 프로필(Active Profile)을 설정하기에 매우 편리한 위치다.
@Configuration public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.setInitParameter( "spring.profiles.active", "dev"); } }
- 다음으로 환경(environment)에서 직접 프로필을 설정할 수도 있다.
@Autowired private ConfigurableEnvironment env; ... env.setActiveProfiles("someProfile");
- 마찬가지로 컨텍스트 매개변수를 사용하여 웹 애플리케이션의 web.xml 파일에서 활성 프로필을 정의할 수 있다.
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app-config.xml</param-value> </context-param> <context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param>
- 프로필 이름은 JVM 시스템 매개변수를 통해 전달할 수도 있다. 다음 프로필은 애플리케이션 시작 중에 활성화된다.
-Dspring.profiles.active=dev
- Unix 환경에서는 환경 변수를 통해 프로필을 활성화할 수도 있다.
export spring_profiles_active=dev
- 스프링 프로필은 spring.profiles.active 구성 속성을 지정하여 Maven 프로필을 통해 활성화할 수도 있다.
- 모든 Maven 프로필에서 spring.profiles.active 속성을 설정할 수 있다.
<profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <spring.profiles.active>dev</spring.profiles.active> </properties> </profile> <profile> <id>prod</id> <properties> <spring.profiles.active>prod</spring.profiles.active> </properties> </profile> </profiles>
- 해당 값은 아래 application.properties의
{spring.profiles.active}
를 대체하는 데 사용된다.spring.profiles.active={spring.profiles.active}
- 이제 pom.xml에서 리소스 필터링을 활성화해야 한다.
<build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> ... </build>
- 그리고 적용할 Maven 프로필을 전환하기 위해 -P 매개변수를 추가한다.
mvn clean package -Pprod
- 이 명령은 prod 프로필용 애플리케이션을 패키징하고, 애플리케이션이 실행 중일 때 spring.profiles.active의 값으로 prod를 적용한다.
- @ActiveProfile 주석을 사용하면 활성 상태인 프로필을 매우 쉽게 지정하여 테스트를 수행할 수 있다.
@ActiveProfiles("dev")
- 지금까지 프로필을 활성화하는 방법을 여러 가지 살펴보았다. 이제 이들 사이의 우선순위를 알아보자.
- Context parameter in web.xml
- WebApplicationInitializer
- JVM System parameter
- Environment variable
- Maven profile
- 프로필을 지정하지 않는 모든 Bean은 기본 프로필에 속한다.
- 스프링은 다른 프로필이 활성화되어 있지 않을 때 spring.profiles.default 속성을 사용하여 기본 프로필을 설정하도록 지원한다.
- 프로그래밍 방식으로 활성 프로필 목록에 접근하는 방식에 대해 알아보자. 방법은 크게 환경(Environment) 또는 spring.active.profile을 사용하는 두 가지 방법이 있다.
- 다음을 주입하여 Environment 개체에서 활성 프로필에 접근할 수 있다.
public class ProfileManager { @Autowired private Environment environment; public void getActiveProfiles() { for (String profileName : environment.getActiveProfiles()) { System.out.println("Currently active profile - " + profileName); } } }
- spring.profiles.active 속성을 주입하여 프로필에 접근할 수도 있다.
@Value("${spring.profiles.active}") private String activeProfile;
- 여기에서 activeProfile 변수에는 현재 활성 상태인 프로필의 이름이 포함되며, 프로필이 여러 개인 경우 이름이 쉼표로 구분되어 포함된다.
- 그러나 만약 활성 프로필이 없으면 애플리케이션 컨텍스트가 생성되지 않는다. 변수에 주입할 자리 표시자가 없기 때문에 IllegalArgumentException이 발생한다.
- 이 문제를 피하기 위해 콜론(:) 뒤에 기본값을 정의할 수 있다.
@Value("${spring.profiles.active:}") private String activeProfile;
- 이제 활성 프로필이 없으면 활성 프로필에 빈 문자열만 포함된다.
- 그리고 이전 예와 같이 목록에 접근하려면 activeProfile 변수를 쉼표(,)로 나누어 액세스할 수 있다.
public class ProfileManager { @Value("${spring.profiles.active:}") private String activeProfiles; public String getActiveProfiles() { for (String profileName : activeProfiles.split(",")) { System.out.println("Currently active profile - " + profileName); } } }
- 개발 및 프로덕션 두 가지 환경에서 모두 데이터 소스를 구성해야 한다고 해보자.
- 먼저 두 데이터 소스 구현 모두에서 구현해야 하는 공통 인터페이스 DatasourceConfig를 만들 것이다.
public interface DatasourceConfig { public void setup(); }
- 다음으로 개발 환경을 위한 데이터 소스를 구성하자.
@Component @Profile("dev") public class DevDatasourceConfig implements DatasourceConfig { @Override public void setup() { System.out.println("Setting up datasource for DEV environment. "); } }
- 그리고 그 다음으로 프로덕션 환경을 위한 데이터 소스를 구성하자.
@Component @Profile("production") public class ProductionDatasourceConfig implements DatasourceConfig { @Override public void setup() { System.out.println("Setting up datasource for PRODUCTION environment. "); } }
- 이제 테스트를 만들고 DatasourceConfig 인터페이스를 주입하자. 활성 프로필에 따라 스프링은 DevDatasourceConfig 또는 ProductionDatasourceConfig 빈을 주입할 것이다.
public class SpringProfilesWithMavenPropertiesIntegrationTest { @Autowired DatasourceConfig datasourceConfig; public void setupDatasource() { datasourceConfig.setup(); } }
- 만약 dev 프로필이 활성화되어 있다면 스프링은 DevDatasourceConfig 객체를 주입한다. setup() 메서드를 호출하면 다음과 같은 결과가 출력된다.
Setting up datasource for DEV environment.
- 스프링 부트는 몇 가지 추가 기능과 함께 지금까지 설명한 모든 프로필 구성을 지원한다.
- 앞의 섹션 4에서 소개한 초기화 매개변수 spring.profiles.active는 스프링 부트에서 속성으로 설정할 수도 있다. 이것은 현재 활성화된 프로필을 정의하기 위해 스프링 부트가 자동으로 선택하는 표준 속성이다.
spring.profiles.active=dev
- 하지만 이 속성은 스프링 부트 2.4부터 ConfigDataException(즉, InvalidConfigDataPropertyException 또는 InactiveConfigDataAccessException)이 발생할 수 있으므로 spring.config.activate.on-profile과 함께 사용할 수 없다.
- 프로그래밍 방식으로 프로필을 설정하려면 SpringApplication 클래스를 사용할 수도 있다.
SpringApplication.setAdditionalProfiles("dev");
- 스프링 부트에서 Maven을 사용하여 프로필을 설정하려면 pom.xml의 spring-boot-maven-plugin에서 프로필 이름을 지정할 수 있다.
<plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <profiles> <profile>dev</profile> </profiles> </configuration> </plugin> ... </plugins>
- 그리고 스프링 부트 관련 Maven 명령을 실행하자.
mvn spring-boot:run
- 스프링 부트가 제공하는 가장 중요한 프로필 관련 기능은 프로필별 속성 파일 이다. 이러한 이름은 application-{profile}.properties 형식으로 지정해야 한다.
- 스프링 부트는 모든 프로필에 대해 application.properties 파일의 속성을 자동으로 로드하고 지정된 프로필에 대해서만 프로필별 .properties 파일에 있는 속성을 로드한다.
- 예를 들어 application-dev.properties 및 application-production.properties라는 두 개의 파일을 사용하여 개발 및 프로덕션 프로필에 대해 서로 다른 데이터 소스를 구성할 수 있다.
- application-production.properties 파일에서는 MySql 데이터 소스를 설정할 수 있다.
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/db spring.datasource.username=root spring.datasource.password=root
- 한편, application-dev.properties 파일에서는 동일한 속성에 H2 데이터베이스 데이터 소스를 구성할 수 있다.
spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 spring.datasource.username=sa spring.datasource.password=sa
- 이러한 방식으로 다양한 환경에 대해 다양한 구성을 쉽게 제공할 수 있다.
- 스프링 부트 2.4 이전에는 프로필 관련 문서로 프로필을 활성화하는 것이 가능했다. 하지만 이후 버전에서는 이러한 상황에서 프레임워크가 (다시) InvalidConfigDataPropertyException 또는 InactiveConfigDataAccessException을 발생시킨다.
- 별도의 환경에 대한 속성 정의를 보다 단순히 하기 위해 동일한 파일의 모든 속성을 묶고 구분 기호를 사용하여 프로필을 나타낼 수도 있다.
- 스프링 부트 2.4부터 이전에 지원되는 YAML 외에도 속성 파일에 대한 다중 문서 파일에 대한 지원을 확장했다. 이제 동일한 application.properties에서 dev 및 production 속성을 지정할 수 있다.
my.prop=used-always-in-all-profiles #--- spring.config.activate.on-profile=dev spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/db spring.datasource.username=root spring.datasource.password=root #--- spring.config.activate.on-profile=production spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 spring.datasource.username=sa spring.datasource.password=sa
- 이 파일은 스프링 부트에서 위에서 아래로 읽는다. 즉, 위의 예에서 my.prop과 같은 일부 속성이 마지막에 한 번 더 발생하면 가장 마지막 값이 적용된다.
- 스프링 부트 2.4에서는 프로필 그룹 기능이 추가되었다. 이름에서 알 수 있듯이 이제 유사한 프로필을 함께 그룹화할 수 있다.
- 프로덕션 환경에 대해 여러 구성 프로필이 있다고 하자. 그리고 프로덕션 환경의 데이터베이스용 proddb와 스케줄러용 prodquartz가 있다고 해보자.
- application.properties 파일을 통해 이러한 프로필을 한 번에 모두 활성화하려면 다음과 같이 지정할 수 있다.
spring.profiles.group.production=proddb,prodquartz
- 결과적으로 프로덕션 프로필을 활성화하면 proddb 과 prodquartz 이 모두 활성화된다.