首页 > 代码库 > ResourceBundle 实现定时重载 properties 文件

ResourceBundle 实现定时重载 properties 文件

简介

在 JDK 1.6 中,新增了一个类 ResourceBundle.Control 可实现简单的自动重载,其实这是一个实现控制 ResourceBundle 缓存策略的类。该类有两个方法涉及到缓存:getTimeToLive、needsReload

其中 getTimeToLive 方法表示 ResourceBundle 实例在缓存中的生存时间,可以是某个具体的微秒值,也可以是不缓存(TTL_DONT_CACHE),或者永久缓存(TTL_NO_EXPIRATION_CONTROL)。

一旦设置了具体的微秒值时,假设 getTimeToLive 返回的是1000,那么每次在调用 getBundle 的时候,只要当前时间和载入资源的时间之差比TimeToLive要大,就要调用needsReload 方法来判断是否需要重新加载 ResourceBundle 。needsReload只返回 true 或者 false,表示是否重加载。


源码浅析


我们可以通过源码来看看具体的逻辑:(不感兴趣可以跳到最后直接看如何定时重载properties文件)

1、首先当我们没有禁用缓存时,首次加载资源文件时,系统会将文件缓存,此时会为缓存设置一个过期时间,而这个过期时间就是根据TimeToLive加上当前时间算出来的:

    private static final void setExpirationTime(CacheKey cacheKey, Control control) {
	long ttl = control.getTimeToLive(cacheKey.getName(),
					 cacheKey.getLocale());
	if (ttl >= 0) {
	    // If any expiration time is specified, set the time to be
	    // expired in the cache.
	    long now = System.currentTimeMillis();
	    cacheKey.loadTime = now;
	    cacheKey.expirationTime = now + ttl;
	} else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
	    cacheKey.expirationTime = ttl;
	} else {
	    throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
	}
    }


2、而我们调用getBundle(..)去获取资源包时,首先会去缓存中找,若找到了,还需要判断是否超时,超时了就要判断是否过期(是否需要重载)

		    synchronized (bundle) {
			expirationTime = key.expirationTime;
			if (!bundle.expired && expirationTime >= 0 &&
			    expirationTime <= System.currentTimeMillis()) {
			    try {// 超时之后判断needToReload,这个返回true才是真正的过期
				bundle.expired = control.needsReload(key.getName(),
								     key.getLocale(),
								     key.getFormat(),
								     key.getLoader(),
								     bundle,
								     key.loadTime);
			    } catch (Exception e) {
				cacheKey.setCause(e);
			    }
			    if (bundle.expired) {
				// If the bundle needs to be reloaded, then
				// remove the bundle from the cache, but
				// return the bundle with the expired flag
				// on.
				bundle.cacheKey = null;
				cacheList.remove(cacheKey, bundleRef);
			    } else {
				// Update the expiration control info. and reuse
				// the same bundle instance
				setExpirationTime(key, control);
			    }
			}
		    }

3、若需要重载的话,那就重新加载资源


定时重载 properties 文件

根据上面说的,我们只需要实现自己的Control就可以了

package bundle.test;

import java.util.Locale;
import java.util.ResourceBundle;

/**
 * 自动刷新资源文件
 * @author Zhu
 *
 */
public class ResourceTester {

	private final static MyResourceBundleControl ctl = new MyResourceBundleControl();

	/**
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		System.out.println(getBundle().getString("cancelKey"));
		Thread.sleep(5000);
		System.out.println(getBundle().getString("cancelKey"));
	}

	private static ResourceBundle getBundle() {
		return ResourceBundle.getBundle("res", Locale.getDefault(), ctl);
	}

	/**
	 * 重载控制器
	 */
	private static class MyResourceBundleControl extends ResourceBundle.Control {

		@Override
		public long getTimeToLive(String baseName, Locale locale) {
			return 1000;
		}

		@Override
		public boolean needsReload(String baseName, Locale locale,
				String format, ClassLoader loader, ResourceBundle bundle,
				long loadTime) {
			return true;
		}
	}
}

这样只要间隔时间超过1s去访问资源包,都能取到最新的~




ResourceBundle 实现定时重载 properties 文件