프로필
1. 프로필
개발을 진행하는 동안에는 실제 서비스 목적으로 운영중인 DB를 이용할 수는 없다. 개발하는 동안에는 개발용 DB를 따로 사용하거나 개발 PC에 직접 DB를 설치해서 사용한다.
실제 서비스 환경에서는 웹 서버와 DB 서버가 서로 다른 장비에 설치된 경우가 많다. 개발 환경에서 사용한 DB 계정과 실 서비스 환경에서 사용할 DB 계정이 다른 경우도 흔하다. 즉 개발을 완료한 어플리케이션을 실제 서버에 배포하려면 실 서비스 환경에 맞는 JDBC 연결 정보를 사용해야 한다.
- 단순 설정 변경
실 서비스 장비에 배포하기 전에 설정 정보를 변경하고 배포하는 방법을 사용할 수도 있다.- 이 방법은 너무 원시적이다.
- 실수하기 쉽다.
- 프로필(profile)
이런 실수를 방지하는 방법은 처음부터 개발 목적 설정과 실 서비스 목적의 설정을 구분해서 작성하는 것이다. 이를 위한 스프링 기능이 프로필(profile)이다.
프로필은 논리적인 이름으로서 설정 집합에 프로필을 지정할 수 있다. 스프링 컨테이너는 설정 집합 중에서 지정한 이름을 사용하는 프로필을 선택하고 해당 프로필에 속한 설정을 이용해서 컨테이너를 초기화할 수 있다.
예를 들어 로컬 개발 환경을 위한 DataSource 설정을 “dev” 프로필로 지정하고 실 서비스 환경을 위한 DataSource 설정을 “real” 프로필로 지정한 뒤, “dev” 프로필을 사용해서 스프링 컨테이너를 초기화할 수 있다. 그러면 스프링은 다음과 같이 “dev” 프로필에 정의된 빈을 사용하게 된다.
1.1 @Configuration 설정에서 프로필 사용하기
@Configuration 애노테이션을 이용한 설정에서 프로필을 지정하려면 @Profile 애노테이션을 이용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package config;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@Profile("dev")
public class DsDevConfig {
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost/spring5fs?characterEncoding=utf8");
ds.setUsername("root");
ds.setPassword("1234");
ds.setInitialSize(2);
ds.setMaxActive(10);
ds.setTestWhileIdle(true);
ds.setMinEvictableIdleTimeMillis(60000 * 3);
ds.setTimeBetweenEvictionRunsMillis(10 * 1000);
return ds;
}
}
- 9행 : @Profile은 “dev”를 값으로 갖는다. 스프링 컨테이너를 초기화할 때 “dev” 프로필을 활성화하면 DsDevConfig 클래스를 설정으로 사용한다.
“dev”가 아닌 “real”로 프로필을 활성화했을 때 사용할 설정 클래스는 다음과 같이 @Profile 애노테이션의 값으로 “real”을 지정한다.
1
2
3
4
5
@Configuration
@Profile("real")
public class DsRealConfig {
...
}
DsDevConfig 클래스와 DsRealConfig 클래스는 둘 다 이름이 “dataSource”인 DataSource 타입의 빈을 설정하고 있다.
두 “dataSource” 빈 중에서 어떤 빈을 사용할지는 활성화한 프로필에 따라 달라진다. “dev” 프로필을 활성화하면 @Profile(“dev”) 애노테이션을 붙인 설정 클래스의 dataSource 빈을 사용하고 “real” 프로필을 활성화하면 @Profile(“real”) 애노테이션을 붙인 설정 클래스의 dataSource 빈을 사용한다.
특정 프로필을 선택하려면 컨테이너를 초기화하기 전에 setActiveProfile() 메서드를 사용해서 프로필을 선택해야 한다.
1
2
3
4
AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev")
context.register(MemberConfi.class, DsDevConfig.class, DsRealConfig.class);
context.refresh();
-
getEnvironment() 메서드는 스프링 실행 환경을 설정하는데 사용되는 Environment를 리턴한다. 이 Environment의 setActiveProfiles() 메서드를 사용해서 사용할 프로필을 선택할 수 있다. 위 코드는 “dev”를 값으로 주었으므로 “dev” 프로필에 속한 설정이 사용된다. 따라서 DsDevConfig에 정의된 “dataSource” 빈을 사용한다.
-
프로필을 사용할 때 주의할 점은 설정 정보를 전달하기 전에 어떤 프로필을 사용할지 지정해야 한다는 점이다. 위 코드를 보면 setActiveProfiles() 메서드로 “dev” 프로필을 사용한다고 설정한 뒤에 register() 메서드로 설정 파일 목록을 지정했다. 그런 뒤 refresh() 메서드를 실행해서 컨테이너를 초기화했다. 이 순서를 지키지 않고 프로필을 선택하기 전에 설정 정보를 먼저 전달하면 프로필을 지정한 설정이 사용되지 않기 때문에 설정을 읽어오는 과정에서 빈을 찾지 못해 Exception이 발생한다.
- 두 개 이상의 프로필을 활성화하고 싶다면 다음과 같이 각 프로필 이름을 메서드에 파라미터로 전달한다.
1
context.getEnvironment.setActiveProfiles("dev", "mysql");
- 프로필을 선택하는 또 다른 방법은 spring.profiles.active 시스템 프로퍼티에 사용할 프로필 값을 지정하는 것이다. 두 개 이상의 경우 사용할 프로필을 콤마로 구분해서 설정하면 된다. 시스템 프로퍼티는 명령행에서 -D 옵션을 이용하거나 System.setProperty()를 이용해서 지정할 수 있다. 아래 코드는 -D 옵션을 이용한 설정 예이다.
1
java _Dspring.profiles.active=dev main.Main
위와 같이 시스템 프로퍼티로 프로필을 설정하면 setActiveProfiles() 메서드를 사용하지 않아도 “dev” 프로필이 활성화된다.
1
2
3
4
5
6
7
// 명령행에 -Dspring.profiles.active=dev 옵션을 주거나
// System.setProperty("spring.profiles.active", "dev") 코드로
// spring.profiles.active 시스템 프로퍼티 값을 "dev"로 설정하면
// "dev" 프로필을 활성화한다.
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
MemberConfig.class, DsDevConfig.class, DsRealConfig.class);
자바의 시스템 프로퍼티뿐만 아니라 OS의 “spring.profiles.active” 환경 변수에 값을 설정해도 된다. 프로필 우선 순위는 다음과 같다.
- setActiveProfiles()
- 자바 시스템 프로퍼티
- OS 환경 변수
1.2 @Configuration을 이용한 프로필 설정
중첩 클래스를 이용해서 프로필 설정을 한 곳으로 모을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
public class MemberConfigWithProfile{
@Autowired
private DataSource dataSource;
@Bean
public MemberDao memberDao(){
return new MemberDao(dataSource);
}
@Configuration
@Profile("dev")
public static class DsDevConfig{
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost/spring5fs? characterEncoding=utf8");
...
return ds;
}
}
중첩된 @Configuration 설정을 사용할 때 주의할 점은 중첩 클래스는 static이어야 한다는 점이다.
1.3 다수 프로필 설정
스프링 설정은 두 개 이상의 프로필 이름을 가질 수 있다. 아래 코드는 real과 test프로필을 갖는 설정 예이다. real 프로필을 사용할 때와 test 프로필을 사용할 떄 모두 해당 설정을 사용한다.
1
2
3
4
@Configuration
@Profile("real,test")
public class DataSourceJndiConfig
...
프로필 값을 지정할 때 다음 코드처럼 느낌표(!)를 사용할 수도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@Profile("!real")
public class DsDevConfig{
@Bean(destroyMethod = "close")
public DataSource dataSource(){
DataSource ds = new DataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
...
return ds;
}
}
“!real”값은 “real” 프로필이 활성화되지 않을 때 사용한다는 것을 의미한다. 보통 “!프로필” 형식은 프로필이 사용되지 않을 때 기본으로 사용할 설정을 지정하는 용도로 사용된다.
1.4 어플리케이션에서 프로필 설정하기
웹 어플리케이션의 경우에도 spring.profiles.active 시스템 프로퍼티나 환경 변수를 사용해서 사용할 프로필을 선택할 수 있다. 그리고 web.xml에서 다음과 같이 spring.profiles.active 초기화 파라미터를 이용해서 프로필을 선택할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>dev</param-value>
</init-param>
...
</servlet>
Ref.
- 최범균, 스프링프로그래밍입문5, 가메출판사.