`
hrtc
  • 浏览: 54761 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

动态加载资源文件

    博客分类:
  • java
阅读更多

问题

对于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。另一种方案是使用代理每次访问属性时查看文件是否修改,但是效率上比不上这种。

分享到:
评论
2 楼 LucasLee 2009-07-07  
你这个解决方法最大的问题在于,需要使用你的PropertiesEx替换通行的Properties类。
如果全部代码都是自己写的,当然问题不大;
如果使用了struts等框架,而这些框架内使用了Properties类,你的方案就没办法了。
1 楼 my_lovelove 2009-01-18  
不错,谢谢分享

相关推荐

    wxWidget 动态加载资源文件XRC的demo

    本项目名为"wxWidget动态加载资源文件XRC的demo",它提供了一个简单的示例,演示如何在运行时动态加载由XRC定义的资源。这种做法在需要根据用户需求或环境变化灵活调整界面的程序中非常有用。下面我们将深入探讨这个...

    android动态加载外部资源文件

    在Android开发中,动态加载外部资源文件是一种常见的需求,它能增强应用的灵活性和可扩展性。本主题主要探讨如何在Android程序运行时加载不同apk中的资源,包括图片、文字和颜色等。以下是对这个话题的详细阐述: ...

    WPF动态调用资源文件

    在Windows Presentation Foundation(WPF)框架中,动态调用资源文件是一种常见的技术,它使得开发者能够在运行时根据需求加载和应用不同的资源。标题中的“WPF动态调用资源文件”特指在WPF应用程序中,如何根据用户...

    VB.NET调用资源文件图片

    此外,还将涉及如何添加资源文件到项目中,以及如何通过代码访问这些资源。 #### 添加资源文件到VB.NET项目 在开发VB.NET应用程序时,经常需要将图片、文本等资源文件嵌入到项目中,以方便使用。这些资源文件可以是...

    动态加载外部JS文件

    动态加载外部JS文件是网页开发中的一个重要技术,它允许网页在需要时按需加载JavaScript资源,从而提高页面的加载速度,优化用户体验,并有效地管理复杂的项目结构。以下将详细阐述动态加载的原理、方法以及相关实践...

    Delphi中资源文件的使用

    动态资源文件是指在运行时动态加载资源文件的方式,这种方式可以使得项目在运行时加载不同的资源文件,从而实现多语言程序或主题切换。 Delphi 附带的资源编辑器 ImageEdit 只能编辑位图、图标和光标,无法加入...

    DuiLib_Ultimate 加载资源文件三种方法.zip

    本文将详细解析标题为"DuiLib_Ultimate 加载资源文件三种方法.zip"的压缩包文件中涉及到的Duilib加载资源的方法,并结合描述与标签,深入探讨这四种方式。 首先,我们来逐一分析Duilib加载资源的四种方式: 1. **...

    ue4动态加载资源路径信息

    在动态加载资源的场景中,这个文件可能会影响到项目的模块配置和资源的加载策略。 7. **Source目录**:源代码目录包含了实现动态加载逻辑的C++类和脚本。在这里,你可能会编写自定义的`Factory`类来生成资产,或者...

    动态加载资源

    在动态加载的场景下,ZIP文件常被用来存放大量的资源,比如纹理、音频、模型等。程序在运行时可以根据需要解压并加载特定的资源,而非一次性加载所有内容。 介绍.txt文件可能包含了关于这个动态加载方法的详细说明...

    动态调用资源文件做为最小化系统托盘

    要动态加载资源文件作为系统托盘图标,我们需要以下步骤: 1. **包含资源文件**:在你的项目中,确保已经包含资源文件,并在编译时将其链接到可执行文件中。这可以通过设置项目属性或者在源代码中包含资源头文件(....

    资源文件的建立和释放

    2. **添加资源**: 在资源编辑器中,你可以添加各种类型的资源,比如对话框、图标、字符串表、位图、菜单等。只需在资源类型列表中选择你需要的类型,然后添加相应的资源项。 3. **资源代码编写**: 对于`.rc`文件,...

    javascript函数动态加载javascript文件

    在实际项目中,为了提高页面加载速度和优化用户体验,我们常常需要按需加载JavaScript文件,而不是一次性加载所有资源。这正是"javascript函数动态加载javascript文件"这一主题的核心所在。 动态加载JavaScript文件...

    vue动态加载js.zip

    因此,需要在运行时动态地将新的JavaScript文件添加到DOM中,以实现按需加载。 实现Vue动态加载JavaScript的基本步骤如下: 1. 创建Script元素:在JavaScript中,我们可以使用`document.createElement('script')`...

    从资源文件中释放dll等文件

    实现功能:有些程序运行需要加载dll,为了减少文件数量或防止dll被发现,可以在编译阶段将dll文件加密后添加到可执行程序的资源文件中,该程序实现了(1)读取资源文件并释放到内存中(没有加解密,明文存储,但是...

    火山PC写出内置资源文件例子

    这与读取内置资源文件有所不同,读取是加载程序启动时已包含的数据,而写出则是在程序运行过程中创建或修改文件。 要写出资源文件,你需要使用火山PC提供的资源操作命令。例如,对于图片资源,可以先通过资源ID加载...

    加载资源文件类

    资源文件加载类 这里是用的是class getResourceAsStream &quot;path&quot; 来加载资源文件的

    加载资源文件的PDF

    在Android开发中,加载资源文件,尤其是PDF文档,是一个常见的需求。这个"加载资源文件的PDF"项目提供了一个完美的示例,演示了如何在Android应用中实现PDF的加载、缩放以及保持清晰度。以下是对这个项目的详细解析...

    vb资源文件RES用法

    本文将详细介绍RES资源文件的概念、用途以及如何在VB6.0项目中加载和使用这些资源。 #### 一、RES资源文件概述 RES资源文件是一种特殊的文件格式,用于存储应用程序中使用的各种资源,如图标、位图、字符串表等。...

    WKWebView优先加载本地资源文件

    针对"WKWebView优先加载本地资源文件"这一主题,实现方法通常是通过拦截WKWebView的网络请求并替换为本地资源。这涉及到WKWebView的请求拦截机制,即WKNavigationDelegate中的`webView(_:decidePolicyFor:)`方法。在...

    vue动态加载外部依赖js代码实现

    - **异步加载**: 在需要加载较大文件或非关键路径资源时,推荐使用异步加载技术,以提高页面首屏加载速度。 - **按需加载**: 对于不常用的或只在特定条件下使用的功能,采用按需加载策略可以显著减少初始加载时间...

Global site tag (gtag.js) - Google Analytics