ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [06] ApplicationContext - EnvironmentCapable interface
    Spring/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는 여러곳에서 받아올 수 있으며 참조하는 우선순위 별로 나열하면 다음과 같습니다.

    1. ServletConfig 매개변수
    2. ServletContext 매개변수
    3. JNDI (java:comp/env/)
    4. JVM system property (-Dkey="value")
    5. 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 입력

     

    VM option으로 지정한 property를 성공적으로 읽어오는 것을 확인할 수 있습니다.

    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를 읽어옴을 확인할 수 있습니다.

    properties file의 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);
        }
    }

     

    댓글

Designed by Tistory.