ApplicationContext에서 제공하는 또 다른 중요한 기능중의 하나인 Environment에 대해서 살펴보자.
AppConfiguration
@SpringBootApplication을 이용하면 PropertySource안해도 된다!
기본으로 application.properties, application.yaml 파일을 읽기 때문이다.
OrderTester.java
getProperty를 통해 kdt.version값을 가져올 수 있다.
OrderProperties
package org.prgms.order;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
@Component
public class OrderProperties implements InitializingBean {
@Value("${kdt.version:v0.0.0}") // kdt.version 값을 못읽으면 v0.0.0 default 값
private String version;
@Value("3")
private Integer minimumOrderAmount;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(MessageFormat.format("version -> {0}", version));
System.out.println(MessageFormat.format("minimumOrderAmount -> {0}", minimumOrderAmount));
}
}
값을 바꿀 수 있음. InitializingBean을 통해 먼저 호출 된다.!!
application.properties
version = v1.0.0
kdt.version = v1.0.0
kdt.support-vendors = a,b,c,d,e,f,g
kdt.minimum-order-amount = 1
application.yaml
kdt:
version: "v1.0.0"
support-vendors:
- a
- b
- c
스프링 프로파일은 애플리케이션 설정 일부를 분리하여 특정 환경에서만 사용 가능하다. 프로파일을 이용하면 여러 빈 정의들이 특정 프로파일에서만 동작하게 할수도 있고 특정 프로퍼티들을 특정 프로파일로 정의해서 해당 프로파일이 엑티브일때 적용되게 할 수도 있다. 빈 정의와 프로퍼티들에 프로파일을 적용해 보자.
우선 빈 정의시 프로파일을 적용
@Repository
@Profile("local")
public class MemoryVoucherRepository implements VoucherRepository, InitializingBean {
@Repository
@Profile("dev")
public class JdbcVoucherRepository implements VoucherRepository {
@Repository
@Profile("dev")
public class JdbcVoucherRepository implements VoucherRepository {
package org.prgrms.kdt;
import org.prgrms.kdt.order.OrderItem;
import org.prgrms.kdt.order.OrderProperties;
import org.prgrms.kdt.order.OrderService;
import org.prgrms.kdt.order.VersionProvider;
import org.prgrms.kdt.voucher.FixedAmountVoucher;
import org.prgrms.kdt.voucher.JdbcVoucherRepository;
import org.prgrms.kdt.voucher.VoucherRepository;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.util.Assert;
import java.text.MessageFormat;
import java.util.*;
public class OrderTester {
public static void main(String[] args) {
// 프로파일을 적용하고 리플레쉬를 해줘야합니다. 안그러면 이미 디폴트 프로파일로 읽어져서 원하는 결과를 얻을 수 없습니다.
var applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("dev");;
applicationContext.register(AppConfiguration.class);
applicationContext.refresh();
var orderService = applicationContext.getBean(OrderService.class);
var voucherRepository = applicationContext.getBean(VoucherRepository.class);
System.out.println(MessageFormat.format("is JdbcRepo -> {0}", voucherRepository instanceof JdbcVoucherRepository));
System.out.println(MessageFormat.format("is JdbcRepo -> {0}", voucherRepository.getClass().getCanonicalName()));
var voucher = voucherRepository.insert(new FixedAmountVoucher(UUID.randomUUID(), 10L));
var order = orderService.createOrder(UUID.randomUUID(), new ArrayList<OrderItem>() {{
add(new OrderItem(UUID.randomUUID(), 100, 1));
}}, voucher.getVoucherId());
Assert.isTrue(order.totalAmount() == 90L,
MessageFormat.format("totalAmount({0}) is not 90L", order.totalAmount()));
}
}
다음으로 프로파일에 적용해 보자.
servers:
- dev.bar.com
- foo.bar.com
---
spring.config.activate.on-profile: local
kdt:
version: v1.0
support-vendors:
- "a"
- "b"
- "c"
- "d"
minimum-order-amount: 1
description: |- #-에 따라 마지막 줄마꿈이 포함되거나 안포함된다. -있으면 안포함
line 1
line 2
line 3
---
spring.config.activate.on-profile: dev
kdt:
version: v1.0-dev
support-vendors:
- "dev-a"
- "dev-b"
minimum-order-amount: 0
description: |-
dev
application.yml
var applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("dev");;
applicationContext.register(AppConfiguration.class);
applicationContext.refresh();
var version = applicationContext.getEnvironment().getProperty("kdt.version");
var supportVendors = applicationContext.getEnvironment().getProperty("kdt.support-vendors");
var description = applicationContext.getEnvironment().getProperty("kdt.description");
System.out.println(MessageFormat.format("getVersion from env -> {0}", version));
System.out.println(MessageFormat.format("supportVendors from env -> {0}", supportVendors));
System.out.println(MessageFormat.format("description from env -> {0}", description));
var orderProperties = applicationContext.getBean(OrderProperties.class);
System.out.println(MessageFormat.format("getVersion -> {0}", orderProperties.getVersion()));
System.out.println(MessageFormat.format("getMinimumOrderAmount -> {0}", orderProperties.getMinimumOrderAmount()));
System.out.println(MessageFormat.format("getSupportVendors -> {0}", orderProperties.getSupportVendors()));
System.out.println(MessageFormat.format("description -> {0}", orderProperties.getDescription()));
dev → local로 변경하면 이상하게 프로퍼티는 안바뀌지만 주입되는 빈은 변경되는 것을 볼 수있습니다. 스프링 프레임워크는 프로파일에 대한 빈 정의 만을 지원하고 사실 프로파일별 프로퍼티에 대한 변경은 스프링부트에서 지원하는 기능입니다.
스프링부트의 SpringApplication를 사용하기 전에 우선 활성 프로파일을 정의할수 있는 다른 방법들을 보겠습니다.
스프링 활성 프로파일에 대한 정의는 다양한 곳에서 가능합니다. 방금 한 것 처럼 애플리케이션 코드상에 직접 세팅할 수도 있지만 JVM의 시스템 속성
,명령줄 인수
, OS의 환경변수
, 프로퍼티의 속성
에서도 가능합니다.
하나씩 한번 살펴보도록 할게요.
그럼 이제 KdtApplication 을 변경해볼가요.
package org.prgrms.kdt;
import org.prgrms.kdt.order.Order;
import org.prgrms.kdt.order.OrderProperties;
import org.prgrms.kdt.order.OrderRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import java.text.MessageFormat;
@SpringBootApplication
@ComponentScan(basePackages = {"org.prgrms.kdt.order", "org.prgrms.kdt.voucher", "org.prgrms.kdt.config"})
public class KdtApplication {
public static void main(String[] args) {
var context = SpringApplication.run(KdtApplication.class, args);
var orderProperties = context.getBean(OrderProperties.class);
System.out.println(MessageFormat.format("getVersion -> {0}", orderProperties.getVersion()));
System.out.println(MessageFormat.format("getMinimumOrderAmount -> {0}", orderProperties.getMinimumOrderAmount()));
System.out.println(MessageFormat.format("getSupportVendors -> {0}", orderProperties.getSupportVendors()));
System.out.println(MessageFormat.format("getDescription -> {0}", orderProperties.getDescription()));
}
}
코드상에서 변경하려면 다음과 같이 해야합니다.
var springApplication = new SpringApplication(KdtApplication.class);
springApplication.setAdditionalProfiles("dev");
var context = springApplication.run();
springApplication.setAdditionalProfiles("dev");이거를 쓰지 않고
스프링 부트에서는 설정할 수 있는 방법이 다양하다.(Edit configuration)
Active profiles에 dev라고 설정하기( 밑에 사진 참조)
Program argument에 설정하기( --spring.profiles.active = local)