-
[06] ApplicationContext - EnvironmentCapable interfaceSpring/Spring 핵심 기술 2020. 4. 16. 10:52반응형
EnvironmentCapable은 Profile과 Property를 다루는 interface입니다. ApplicatioinContext는 EnvironmentCapable을 상속받기 때문에 IoC Container에서 Profile과 Property를 다룰 수 있습니다.
public interface ApplicationContext extends EnvironmentCapable { ... }
[Profile]
Profile은 환경에 따라 사용할 bean들의 묶음을 미리 정해놓고 필요에 따라 선택하여 사용할 수 있는 기능을 말합니다. 이를 활용하여 개발환경과 배포환경 또는 각각의 다른 배포환경 별로 profile을 만들어 놓고 환경에 따라 원하는 profile로 전환하여 그에 상응하는 bean들로 application을 구동하도록 할 수 있습니다.
profile 사용 준비
Profile을 사용하기 위해서는 우선 Environment를 가져와야 합니다. Environment는 ApplicationContext의 getEnvironment() 메서드를 통해 가져올 수 있습니다.
@Component public class AppRunner implements ApplicationRunner { @Autowired ApplicationContext ctx; public void run(ApplicationArguments args) throws Exception { Environment environment = ctx.getEnvironment(); //Environment를 가져온다. } }
profile의 확인
Environment의 profile은 default profile과 active profile이 있습니다. default profile은 어떤 profile에도 묶이지 않은 bean들이 속해있는 profile이고 active profile은 사용자가 생성한 profile 중 현재 사용중인 profile들을 말합니다. 적용 중인 profile들을 확인하기 위해 Environment의 getActiveProfiles()와 getDefaultProfiles() method를 사용할 수 있습니다.
@Component public class AppRunner implements ApplicationRunner { @Autowired ApplicationContext ctx; public void run(ApplicationArguments args) throws Exception { Environment environment = ctx.getEnvironment(); System.out.println(Arrays.toString(environment.getActiveProfiles())); System.out.println(Arrays.toString(environment.getDefaultProfiles())); } }
bean에 profile 지정하기
class에 @Component 어노테이션과 함께 @Profile("프로파일_이름")를 사용해 class 하위에 선언된 모든 bean들에 대해 "프로파일_이름"의 profile을 지정할 수 있습니다.
profile 기능에 대한 test를 위한 class와 interface를 먼저 생성해보도록 하겠습니다.
<PetRepository.java>
public interface PetRepository { }
<TestPetRepository.java>
@Repository public class TestPetRepository implements PetRepository { }
test를 위한 class와 interface를 만드셨으면 bean에 profile을 지정합니다.
먼저 @Configuration class 내부에 @Bean을 통해 등록된 bean에 profile을 지정하는 예입니다.
Configuration class를 하나 생성합니다. 여기서는 "DevConfiguration"라는 이름으로 만듭니다.
@Configuration @Profile("dev") public class DevConfiguration { @Bean public PetRepository petRepository() { return new TestPetRepository(); } }
@Profile("dev")를 붙였으므로 DevConfiguration class의 모든 bean에 "dev"라는 이름의 profile이 지정됩니다.
runner class에서 다음과 같이 "dev" profile에 묶어둔 bean을 주입하면 bean type을 찾을 수 없다는 오류 메시지를 만나게 됩니다. 이는 현재 application에 "dev" profile을 사용한다고 명시되지 않았기 때문입니다.
@Component public class AppRunner implements ApplicationRunner { @Autowired PetRepository petRepository; public void run(ApplicationArguments args) throws Exception { System.out.println(petRepository.getClass()); } }
@Configuration 외의 @Component와 그 하위 어노테이션(@Controller, @Service, @Repository)들도 @Profile을 붙여 profile로 관리할 수 있습니다. TestPetRepository.java를 다음과 같이 변경하면 TestPetRepository bean에 "dev" profile이 지정됩니다.
@Repository @Profile("dev") public class TestPetRepository implements PetRepository { }
@Profile의 매개값은 Not, And, Or 연산자를 사용할 수도 있습니다.
- Not : @Profile("!dev") -> "dev" profile이 사용되는 경우 하위의 bean을 사용합니다.
- And : @Profile("dev & test") -> "dev" profile과 "test" profile이 모두 사용되는 경우 하위의 bean을 사용합니다.
- Or : @Profile("dev | test") -> 사용중인 profile에 "dev"나 "test"가 있으면 하위 bean을 사용합니다.
사용할 profile을 지정
application을 실행할 때 VM option을 통해 사용하고자 하는 profile을 지정할 수 있습니다. option은 다음과 같습니다.
-Dspring.profiles.active="dev, test1, test2, ..."
Intellij IDE에서 VM Option을 적용하려먼 Ctrl + Shift + A 로 action shortcut을 열어 검색 창에 "Edit Configuration"이라고 입력 후 enter를 눌러 Run/Debug Configuration 메뉴를 실행합니다. 입력 항목 중 VM Option이 있는데 그 곳에 위의 VM option 문자열을 입력해주고 하단의 "OK" button을 click합니다.
jar file을 직접 실행할 때의 예: java -jar -Dspring.profiles.active="dev" application.jar
profile로 묶인 bean들은 application 실행 시 사용할 profile에 지정해야만 생성과 주입이 가능합니다.
[Property]
Environment의 Perperty는 application에 등록된 여러가지 key, value pair 형태의 property에 접근할 수 있는 기능입니다. key, value pair의 property는 여러곳에서 받아올 수 있으며 참조하는 우선순위 별로 나열하면 다음과 같습니다.
- ServletConfig 매개변수
- ServletContext 매개변수
- JNDI (java:comp/env/)
- JVM system property (-Dkey="value")
- JVM system environment variable (OS 환경변수)
Property의 사용
방법1: Environment.getProperty()를 사용
Environment의 getProperty() method를 사용하여 Property를 읽어올 수 있습니다.
테스트를 위해 runner class를 다음과 같이 변경합니다.
@Component public class AppRunner implements ApplicationRunner { @Autowired ApplicationContext ctx; public void run(ApplicationArguments args) throws Exception { Environment environment = ctx.getEnvironment(); //app.name이라는 Property의 값을 읽어온다. System.out.println(environment.getProperty("app.name")); } }
위의 코드에서 읽어올 property를 VM option으로 -Dapp.name="VM option"이라고 지정하고 application을 실행합니다.
VM option으로 지정한 property를 성공적으로 읽어오는 것을 확인할 수 있습니다.
resources 밑에 properties file을 생성하고 property들을 작성한 뒤 그 값을 읽어올 수도 있습니다.
먼저 testproperty.properties file을 생성하고 내용을 다음과 같이 작성합니다.
app.name = "properties file"
입력된 property를 읽어오기 위해서는 @PropertySource 어노테이션을 사용해야 합니다. @PropertySource 어노테이션의 옵션으로 properties file읠 경로를 지정하면 file 내부에 입력된 property를 참조할 수 있습니다. 실제로 읽어오는지 확인해보기 위해 runner class를 다음과 같이 변경한 후 실행해 봅니다.
@Component @PropertySource("classpath:/testproperty.properties") public class AppRunner implements ApplicationRunner { @Autowired ApplicationContext ctx; public void run(ApplicationArguments args) throws Exception { Environment environment = ctx.getEnvironment(); System.out.println(environment.getProperty("testDave")); } }
여전히 VM option으로 준 property 값이 읽혀옵니다. 즉, Properties file보다 VM option으로 준 property를 우선하여 읽고 있는 것입니다.
VM option을 제거하고 다시 실행해보면 의도했던대로 testproperty.properties의 app.name property를 읽어옴을 확인할 수 있습니다.
방법2: @Value를 사용
String 타입의 변수에 @Value 어노테이션을 주고 옵션으로 참조할 property를 지정하여 해당되는 property 값을 받아올 수 있습니다.
@Component @PropertySource("classpath:/testproperty.properties") public class AppRunner implements ApplicationRunner { @Autowired ApplicationContext ctx; @Value("${app.name}") String appName; public void run(ApplicationArguments args) throws Exception { System.out.println(appName); } }
'Spring > Spring 핵심 기술' 카테고리의 다른 글
[08] ApplicationContext - ApplicationEventPublisher (0) 2020.04.19 [07] ApplicationContext - MessageSource (0) 2020.04.17 [05] ApplicationContext - Bean의 scope (0) 2020.04.14 [04] ApplicationContext - @Component와 Component Scanning (0) 2020.04.14 [03] ApplicationContext - @Autowired를 통한 Dependency Injection (0) 2020.04.13