动态加载资源文件

问题

对于java应用中的一些配置文件每次都需要重新启动服务才能重新加载,非常麻烦,故做了一个动态加载资源的程序。

可选方案

使用监听线程监听文件变化,当文件变化时通知程序重新加载配置文件,用到了事件委托模型和观察者模式类似,如下

公共部分

 

1.Listener接口

package com.hrtc.monitor;

/**
 * 监听器接口
 * Jul 30, 2008 3:02:28 PM
 */
public interface IMonitorListener {
	public void update(MonitorEvent event);
}

 2.Event监听事件顶层类

package com.hrtc.monitor;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 监听事件
 * Jul 30, 2008 3:03:12 PM
 */
public class MonitorEvent {
	private Object lock = new Object();
	private List monitorListenerList = new ArrayList();

	public void addListener(IMonitorListener listener) {
		synchronized (lock) {
			if (!monitorListenerList.contains(listener)) {
				monitorListenerList.add(listener);
			}
		}
	}

	public void removeListener(IMonitorListener listener) {
		synchronized (lock) {
			if (monitorListenerList.contains(listener)) {
				monitorListenerList.remove(listener);
			}
		}
	}

	public void removeAllListener() {
		synchronized (lock) {
			monitorListenerList.clear();
		}
	}

	/**
	 * 触发事件可由子类重载
	 */
	public void fireEvent() {
		synchronized (lock) {
			for (Iterator it = monitorListenerList.iterator(); it.hasNext();) {
				IMonitorListener listener = (IMonitorListener) it.next();
				listener.update(this);
			}
		}
	}
}

 3.主线程监听类

package com.hrtc.monitor;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 监听线程类
 * 
 * Jul 30, 2008 3:03:55 PM
 */
public class MonitorThread extends Thread {
	private List monitorEventList = new ArrayList();
	private long interval;
	private boolean isMonitor = false;
	private Object lock = new Object();
	private static MonitorThread monitor;

	synchronized public static MonitorThread getInstance(long intervalSecond) {
		if (monitor == null) {
			monitor = new MonitorThread(intervalSecond);
		}else{
			monitor.setInterval(intervalSecond);
		}
		return monitor;
	}

	synchronized public static MonitorThread getInstance() {
		if (monitor == null) {
			monitor = new MonitorThread(1);
		}
		return monitor;
	}

	/**
	 * 构造方法
	 * 
	 * @param intervalSecond
	 *            监听间隔时间
	 */
	public MonitorThread(long intervalSecond) {
		this.interval = intervalSecond * 1000;
	}

	public void addEvent(MonitorEvent event) {
		synchronized (lock) {
			if (!monitorEventList.contains(event)) {
				monitorEventList.add(event);
			}
		}
	}

	public void removeEvent(MonitorEvent event) {
		synchronized (lock) {
			if (monitorEventList.contains(event)) {
				monitorEventList.remove(event);
			}
		}
	}

	public void removeAllEvent() {
		synchronized (lock) {
			monitorEventList.clear();
		}
	}

	/**
	 * 监听主方法,每隔一段间隔触发事件列表
	 */
	public void run() {
		if (isMonitor) {
			return;
		}
		isMonitor = true;
		try {
			while (isMonitor) {

				synchronized (lock) {
					for (Iterator it = monitorEventList.iterator(); it
							.hasNext();) {
						MonitorEvent event = (MonitorEvent) it.next();
						event.fireEvent();
					}
				}
				Thread.sleep(interval);

			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			isMonitor = false;
		}
	}

	/**
	 * 结束监听,并不是马上结束只是把标致设为结束
	 */
	public void end() {
		isMonitor = false;
	}

	/**
	 * 是否正在监听
	 * 
	 * @return
	 */
	public boolean isMonitor() {
		return isMonitor;
	}

	public long getInterval() {
		return interval;
	}

	public void setInterval(long interval) {
		this.interval = interval;
	}

}

 应用案例1:可自动检查文件变化的Properties

1.首先定义一个“文件改变事件监听类”继承自MonitorEvent

package com.hrtc.monitor.file;

import java.io.File;
import java.io.IOException;

import com.hrtc.monitor.MonitorEvent;

/**
 * 文件改变监听类
 * Jul 30, 2008 3:07:05 PM
 */
public class FileChangeMonitorEvent extends MonitorEvent {
	private File f;
	private long lastModifiedTime;
	private long lastLength;
	private boolean isChanged = false;

	/**
	 * 
	 * @param f 需要监听的文件
	 */
	public FileChangeMonitorEvent(File f) {
		if (!f.exists()) {
			try {
				throw new IllegalArgumentException("Path "
						+ f.getCanonicalPath() + " dose't exist.");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		this.f = f;
		getFileInfo();
	}

	private void getFileInfo(){
		lastModifiedTime = f.lastModified();
		lastLength = f.length();
	}
	
	/**
	 * 如果文件已改变则触发事件
	 */
	@Override
	public void fireEvent() {
		try {
			f = f.getCanonicalFile();
			isChanged = lastModifiedTime != f.lastModified() || lastLength != f.length();
			if (isChanged) {
				super.fireEvent();
				getFileInfo();
				isChanged = false;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获得监听的文件
	 * @return
	 */
	public File getF() {
		return f;
	}

}

 2.定义PropertiesEx类,以及内部类ReloadPropertiesListener

package com.hrtc.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import com.hrtc.monitor.IMonitorListener;
import com.hrtc.monitor.MonitorEvent;
import com.hrtc.monitor.MonitorThread;
import com.hrtc.monitor.file.FileChangeMonitorEvent;

/**
 * 可自动加载属性变化的属性类
 * Jul 30, 2008 3:10:32 PM
 */
public class PropertiesEx {
	/**
	 * 
	 */
	private static final long serialVersionUID = -6708397622206255544L;

	private MonitorThread monitor;
	private Properties p;
	
	/**
	 * 
	 * @param intervalSecond 监听变化间隔
	 */
	public PropertiesEx(long intervalSecond) {
		monitor = MonitorThread.getInstance(intervalSecond);
	}
	
	/**
	 * 默认更新间隔为1s
	 */
	public PropertiesEx() {
		this(1);
	}

	/**
	 * 加载配置文件
	 * @param f
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public void load(File f) throws FileNotFoundException, IOException {
		p = new Properties();
		p.load(new FileInputStream(f));
		MonitorEvent event = new FileChangeMonitorEvent(f);
		ReloadPropertiesListener listener = new ReloadPropertiesListener();
		event.addListener(listener);
		monitor.addEvent(event);
		if(!monitor.isMonitor()){
			monitor.start();
		}
		
	}

	public String getProperty(String key){
		return p.getProperty(key);
	}

	public Properties getProperties(){
		return p;
	}
	
	/**
	 * 当发生属性文件改变时重新加载属性文件<br>
	 * listener为内部类,为了访问包含类中p成员变量和静止外部访问该类
	 * @author xuwei
	 * Jul 30, 2008 3:11:38 PM
	 */
	private class ReloadPropertiesListener implements IMonitorListener {

		public void update(MonitorEvent event) {
			FileChangeMonitorEvent fcmEvent = (FileChangeMonitorEvent) event;
			try {
				p.load(new FileInputStream(fcmEvent.getF()));
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}

	}

}

 3.测试类

package com.hrtc.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import junit.framework.TestCase;

import com.hrtc.monitor.MonitorThread;

public class PropertiesExTest extends TestCase {

	protected void setUp() throws Exception {
		super.setUp();
	}

       //测试PropertiesEx中的load方法
     	public void testLoad() throws FileNotFoundException, IOException {
		System.out.println("test reload method========");
		PropertiesEx p = new PropertiesEx();
		File f = new File(PropertiesTest.class.getResource("").getPath()
				+ "test.properties");
		p.load(f);
		long t1 = System.currentTimeMillis();
		int count = 10;
		int i = 0;
		try {
                       //循环10秒,在此时间内手动修改配置文件
			while (i < count) {

				String name = p.getProperty("name");
				System.out.println(i + ": name===" + name);
				Thread.sleep(1000);

				i++;
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		long t2 = System.currentTimeMillis();
		System.out.println(t2 - t1);
	}
	
       //测试多个PropertiesEx公用同一MonitorThread
	public void testLoadMultiple() throws FileNotFoundException, IOException {
		System.out.println("test reload multiple========");
		PropertiesEx p1 = new PropertiesEx();
		File f1 = new File(PropertiesTest.class.getResource("").getPath()
				+ "test.properties");
		p1.load(f1);
		PropertiesEx p2 = new PropertiesEx();
		File f2 = new File(PropertiesTest.class.getResource("").getPath()
				+ "test1.properties");
		p2.load(f2);
		long t1 = System.currentTimeMillis();
		int count = 10;
		int i = 0;
		try {
			while (i < count) {

				String name = p1.getProperty("name");
				String value = p2.getProperty("value");
				System.out.println(i + ": " + name + "=" + value);
				Thread.sleep(1000);

				i++;
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		long t2 = System.currentTimeMillis();
		System.out.println(t2 - t1);
               //结束监听,清除监听事件 
		MonitorThread.getInstance().end();
		MonitorThread.getInstance().removeAllEvent();
	}

}
 

配置文件内容,与PropertiesExTest放在同一文件夹下

test.properties

  name=name1

test1.properties

  value=value1

 

总结

上面的同一个MonitorThread甚至可以用到多个不同的事件中,比如除了Properties外还可以定义如xml等其他事件监听,而只用同一个MonitorThread。另一种方案是使用代理每次访问属性时查看文件是否修改,但是效率上比不上这种。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值