본문 바로가기

backend/Spring

스프링 프로퍼티 설정 주입3 - 실시간(run-time)으로 properties Relaod

보통 스프링에서 properties는 DB설정값 처럼 변하지 않는 정적인 데이터를 많이 사용합니다. 하지만, 이러한 프로퍼티값을 변경해야 할 경우가 발생하면 어떻게 해야하나요?



  • 우선, properties를 다시 설정하고 build한 후 다시 재배포하는 과정을 생각할 수 있다.
  • 하지만, 이러한 방법은 재배포를 해야하는 단점이 있다. 이런 경우에 properties의 변경을 감지하여 바로 반영하는 쉬운 방법 있었다.


Apache Commons Configuration 이다
Apache Commons Configuration version 1은 정말 손쉽고 빠르게 적용할 수있는 장점이 있다.
Apache Commons Configuration version 1에 대한 훌륭한 설명을 해주는 글 이에 비해 몇가지 단점도 가지고 있다.


*1. 변경을 감지했을경우 이벤트를 발생시킬수 없다
*2. 안정적인 스레드 구현이 어렵다. 등..

Configuration version 1의 단점

Apache Commons Configuration2은 1의 이러한 단점을 커버할수 있게 업데이트 되었다.

*1. 멀티쓰레드에서의 동기화 보장(병목현상 없음) 등.
*2. relaod시 control 가능. (이벤트를 발생시킬 수 있다) 등…



그럼 commons-configuration2를 구현해보자.




1. org.apache.commons:commons-configuration2 라이브러리를 load한다.

우선, 필요한 아래 라이브러리를 가져온다.(gradle 기준)

 
compile ('org.apache.commons:commons-configuration2:2.1')
compile ('commons-beanutils:commons-beanutils:1.9.3')
 



2. ReloadingFileBasedConfigurationBuilder를 설정.

@Component
public class ReloadTest {
 
 
    private ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder;
 
    @PostConstruct
    void init() {
 
        builder = new
        1. ReloadingFileBasedConfigurationBuilder<>(PropertiesConfiguration.class)
                .configure(new Parameters().fileBased().setFile(new File("src/main/resources/properties/common.properties")));
 
        5. builder.addEventListener(ConfigurationBuilderEvent.CONFIGURATION_REQUEST, new EventListener<Event>() {
              @Override
              public void onEvent(Event event) {
                  System.out.println(" getConfiguration()이 호출 될때마다 이벤트 발생");
              }
          });
 
 
        2. PeriodicReloadingTrigger configReloadingTrigger = new PeriodicReloadingTrigger(
                builder.getReloadingController(), null, 1, TimeUnit.SECONDS);
 
        3. configReloadingTrigger.start();
 
 
    }
 
    public Configuration getCompositeConfiguration() {
          try {
              4. return builder.getConfiguration();
          } catch (ConfigurationException e) {
              e.printStackTrace();
          }
          return null;
      }
 
 
}
  1. ReloadingFileBasedConfigurationBuilder는 configure2에서 제공하는 relaod 전용 클래스이다.
    ReloadingFileBasedConfigurationBuilder에 file경로를 위와 같이 지정해준다.

  2. PeriodicReloadingTrigger는 이름 그대로 리로드 기간을 설정하는 trigger이다.
    TimeUnit.SECONDS, TimeUnit.DAYS와 같이 리로드 감지 시간을 설정할 수 있다.

  3. trigger를 실행 시킨다.

  4. builder.getConfiguration()를 통해서 configuration에 대한 정보를 가져올 수 있다.

  5. 이벤트를 추가 할 수 있다.
  - ConfigurationBuilderEvent.CONFIGURATION_REQUEST :builder.getConfiguration()를 호출 할 때 발생.
  - ConfigurationBuilderEvent.ANY : 어떤 이벤트일 경우든 발생.
  - ConfigurationBuilderEvent.RESET : builder.resetResult() 를 호출 할 때 발생.



3. getCompositeConfiguration()을 통해 configuration정보를 확인.

 
@Component
public class ScheduleTest {
 
    @Value("${test.reload}")
    private String propertyValue;
 
    @Autowired
    private ReloadTest reloadTest;
 
    @Scheduled(cron = "*/10 * * * * *")//10초마다 실행 
    @PostConstruct
    void init(){
        1.System.out.println(propertyValue);
        2.System.out.println(reloadTest.getCompositeConfiguration().getString("test.reload"));
    }
}
  1. Spring의 @value를 통해서 test.relaod 정보를 뿌린다.
  2. getCompositeConfiguration()를 이용해서 configuration을 가져오고 test.reload를 꺼낸다.
  • propertyValue 값과 getString(“test.reload”)를 비교해 보자!



common.properties 변경 후

test.reload=5

common.properties 변경 후

test.reload=6

결과

5 (변경 전 - @value 설정 )
5 (변경 전 - commons-configuration2로 설정)
5 (변경 후 - @value  설정)
6 (변경 후 - commons-configuration2로 설정)



주의 사항

  • relaod하기 위한 properties값을 당연히 @Value로는 접근 할 수 없다. -> commons-configuration2로 접근.
  • builder.getConfiguration()를 통해서만 변경된(감지된) configuration을 전달 받을 수 있다.



결론

  • Apache Commons Configuration2를 활용하여 프로퍼티값의 변경을 감지하고 이벤트를 발생시킬 수 있다.
  • 이러한 점을 활용하여, 우리는 환경 값(properties)을 더욱 효과적이게 사용할 수도 있을 것이다.
    • 이를 테면 dev -> product로 변환하는 작업을 재배포 없이 run-time에 즉시 적용할 수도 있을 것이다.
  • 하지만, properties 값을 잘못 변경하였을 경우를 대비한 방어로직,exception처리를 잘 처리해 놓아야 하겠다. 그렇지 않는다면 실서비스에 엄청난 파장을 끼치지 않을까 두렵기도 하다…
  • 또한, properties 파일의 쓰기에 대한 권한 문제도 잘 처리해야 할 것 같다.

읽어주셔서 감사합니다.

참고: https://commons.apache.org/proper/commons-configuration/userguide/upgradeto2_0.html https://commons.apache.org/proper/commons-configuration/userguide/howto_reloading.html https://mvnrepository.com/artifact/org.apache.commons/commons-configuration2/2.1.1 http://kingbbode.tistory.com/17 https://stackoverflow.com/questions/26150527/how-can-i-reload-properties-file-in-spring-4-using-annotations/42247839#42247839

깃 허브 소스