아키텍처와 함께

블로그 이미지
by gregorio
  • Total hit
  • Today hit
  • Yesterday hit

Spring framework에서는 기본적으로 Properties를 Runtime시에 변경된 설정을 자동으로 반영하는 기능을 제공하고 있지 않다.


Runtime 시 Properites 파일이 변경된 경우 변경된 내용을 읽어서 반여이 필요한 경우 별도로 개발이 필요하다.


먼저 Properties를 읽어서 저장한 후 프로그램에서 사용하기 위해 static으로 ReloadPropertiesUtil을 생성한다.


■ ReloadPropertiesUtil.java

import java.io.InputStream;

import java.util.List;

import java.util.Properties;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;


public class ReloadPropertiesUtil {

private static final Logger LOGGER = LoggerFactory.getLogger(ReloadPropertiesUtil.class);

private static Properties propertyMap = new Properties();

/** Properties file **/

private List<String> propertyFiles;

public void setPropertyFiles(List<String> propertyFiles) {

this.propertyFiles = propertyFiles;

}


/**

*<pre>

* 1.Description: Load Property file when the context is loaded

* 2.Biz Logic:

* 3.Author : LGCNS

*</pre>

* @throws Exception

*/

public void init() throws Exception {

generateProperties();

}

/**

*<pre>

* 1.Description: Reload Properties file

* 2.Biz Logic:

* 3.Author : LGCNS

*</pre>

* @throws Exception

*/

public void reload() throws Exception {

synchronized(this) {

propertyMap.clear();

generateProperties();

}

}

private void generateProperties() throws Exception {

for (String fileName : propertyFiles) {

InputStream fis = BeanUtil.getResoure(fileName);

if (fis == null) {

LOGGER.error("{} file does not exist", fileName);

continue;

}

propertyMap.load(fis);

}

if (LOGGER.isDebugEnabled()) {

propertyMap.list(System.out);

}

}

public static Object get(String key) {

return propertyMap.get(key);

}

public static String getString(String key) {

return propertyMap.get(key) != null ? String.valueOf(propertyMap.get(key)) : "";

}

public static int getInt(String key) {

return propertyMap.get(key) != null ? Integer.parseInt(String.valueOf(propertyMap.get(key))) : 0;

}

public static long getLong(String key) {

return propertyMap.get(key) != null ? Long.parseLong(String.valueOf(propertyMap.get(key))) : 0L;

}

}


ReloadProperties에서는  init과 reload 메소드에서 generateProperties 메소드를 호출하여 Propeties File을 읽어 load하는 기능을 수행한다.


init method는 Spring Framework의 Bean으로 설정하여  IoC Container에 로드될 때 호출되는 메소드이며, reload는 Properties 파일이 변경될 때 호출되는 메소드이다.


다음으로 FileAlterationObserver를 이용하여 Properties  파일의 디렉토리 내의 파일이 변경을 인식하여 서비스를 호출하는 Class를 생성한다.


■BaseFileObserver.java

import java.io.File;

import java.util.ArrayList;

import java.util.List;


import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;

import org.apache.commons.io.monitor.FileAlterationMonitor;

import org.apache.commons.io.monitor.FileAlterationObserver;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Required;

import org.springframework.util.ResourceUtils;


import BizException;

import FileService;

import PropertieFileServiceImpl;


public class BaseFileObserver {


private static final Logger LOGGER = LoggerFactory.getLogger(BaseFileObserver.class);

private List<String> directories;

/** File Check interval (unit : milliseconds**/

private int interval = 500;

/** Service when file or directory is modified **/

private FileService fileService;

@Required

public void setDirectories(List<String> directories) {

this.directories = directories;

}


public void setInterval(int interval) {

this.interval = interval;

}


@Required

public void setFileService(FileService fileService) {

this.fileService = fileService;

}


public BaseFileObserver() {

}


public BaseFileObserver(FileService fileService, List<String> directories) {

this.fileService = fileService;

this.directories = directories;

}


public void init() throws Exception {

for (String dir : directories) {

if (dir.startsWith( ResourceUtils.CLASSPATH_URL_PREFIX)) {

dir = ResourceUtils.getFile(dir).getAbsolutePath();

}

if (LOGGER.isDebugEnabled()) {

LOGGER.debug("File Observe path :: {}", dir);

}

FileAlterationObserver observer = new FileAlterationObserver(dir);

observer.addListener(new FileAlterationListenerAdaptor() {

@Override

public void onDirectoryCreate(File file) {

LOGGER.info("Directory is created : {}", file.getAbsolutePath());

System.out.println("Directory is created : " + file.getAbsolutePath());

try {

fileService.onDirectoryCreate(file);

}

catch(Exception ex) {

throw new BizException(ex.getMessage());

}

}

@Override

public void onDirectoryChange(File file) {

LOGGER.info("Directory is changed : {}", file.getAbsolutePath());

System.out.println("Directory is changed : " +  file.getAbsolutePath());

try {

fileService.onDirectoryChange(file);

}

catch(Exception ex) {

throw new BizException(ex.getMessage());

}

}

@Override

public void onDirectoryDelete(File file) {

LOGGER.info("Directory is deleted : {}", file.getAbsolutePath());

System.out.println("Directory is deleted : " +  file.getAbsolutePath());

try {

fileService.onDirectoryDelete(file);

}

catch(Exception ex) {

throw new BizException(ex.getMessage());

}

}

@Override

public void onFileCreate(File file) {

LOGGER.info("File is created : {}", file.getAbsolutePath());

System.out.println("File is created : " + file.getAbsolutePath());

try {

fileService.onFileCreate(file);

}

catch(Exception ex) {

throw new BizException(ex.getMessage());

}

}

@Override

public void onFileChange(File file) {

LOGGER.info("File is modified : {}", file.getAbsolutePath());

System.out.println("File is modified : " + file.getAbsolutePath());

try {

fileService.onFileChange(file);

}

catch(Exception ex) {

throw new BizException(ex.getMessage());

}

}

@Override

public void onFileDelete(File file) {

LOGGER.info("File is deleted : {}", file.getAbsolutePath());

System.out.println("File is deleted : " +  file.getAbsolutePath());

try {

fileService.onFileDelete(file);

}

catch(Exception ex) {

throw new BizException(ex.getMessage());

}

}

});

/** Create monitor to check file is changed **/

FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);

try {

monitor.start();

}

catch(InterruptedException ie) {

monitor.stop();

}

}


BaseFileObserver는 Properties 파일이 생성, 변경, 삭제되었을 때 FileService의 해당 메소드를 호출한다.


■ PropertieFileServiceImpl.java

import java.io.File;


import org.springframework.beans.factory.annotation.Required;


import ReloadPropertiesUtil;

import FileService;


public class PropertieFileServiceImpl implements FileService {


private ReloadPropertiesUtil propertiesUtil;

@Required

public void setPropertiesUtil(ReloadPropertiesUtil propertiesUtil) {

this.propertiesUtil = propertiesUtil;

}


@Override

public void onDirectoryCreate(File file) throws Exception {

}


@Override

public void onDirectoryChange(File file) throws Exception {

}


@Override

public void onDirectoryDelete(File file) throws Exception {

}


@Override

public void onFileCreate(File file) throws Exception {

propertiesUtil.reload();

}


@Override

public void onFileChange(File file) throws Exception {

propertiesUtil.reload();

}


@Override

public void onFileDelete(File file) throws Exception {

propertiesUtil.reload();

}


}

 


PropertieFileServiceImpl Service는 파일 생성, 삭제, 변경이 발생하는 경우에 ReloadPropertiesUtil의 reload 메소드를 호출한다.



■ Spring Bean 설정

   <bean id="propertiesUtil" class="stis.framework.spring.ReloadPropertiesUtil" init-method="init">

  <property name="propertyFiles">

  <list>

  <value>properties/app.properties</value>

  <value>properties/system.properties</value>

  </list>

  </property>

  </bean>

 

  <bean id="propertyFileObserver" class="stis.framework.file.BaseFileObserver">

  <property name="directories">

  <list>

  <value>classpath:properties</value>

  </list>

  </property>

  <property name="interval" value="500" />

  <property name="fileService" ref="propertyFileService" />

  </bean>

 

  <bean id="propertyFileService" class="stis.framework.spring.service.impl.PropertieFileServiceImpl">

  <property name="propertiesUtil" ref="propertiesUtil" />

   </bean> 


propertiesUtil Bean에서는 properties 파일을  propertyFiles에 주입하여 Context가 로드될 때  init method를 호출하여 해당 파일을 읽도록 설정한다.


propertyFileObserver는 Property 파일이 있는 디렉토리를 directories 속성에 정의하였으며, 파일의 변경 체크 주기를 0.5초 간격으로 수행하도록 설정한다.


또한 propertyFileService에 propertiesUtil을 정의하여 해당 bean에 있는 reload 기능을 수행하도록 한다.


AND

ARTICLE CATEGORY

분류 전체보기 (56)
Spring Framrwork (33)
Linux (1)
APM (1)
Java (8)
python (0)
ant (1)
chart (1)
OS (1)
tomcat (1)
apache (1)
database (0)

RECENT ARTICLE

RECENT COMMENT

CALENDAR

«   2024/10   »
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 28 29 30 31

ARCHIVE

LINK