解析struts2中的监测配置文件中的变化以方便开发时重新加载

    在进行开发时,经常需要修改配置文件,而修改配置文件之后,则必须要重新启动web容器,以重新启动相应的加载框架了。在项目部署时,一般不需要重新加载配置文件。而在开发时,则需要经常重新加载,因为配置文件经常需要被修改。如果重新容器的启动速度较慢,则大大地减慢了开发的速度。如果能够在修改了配置文件之后,即能够重新加载相应的对象,则相比重新启动容器要快一些了。

    在struts2中,就提供了一个在开发时,重新加载配置文件的设置。配置关键字为struts.configuration.xml.reload,当配置此值为true时,在每次请求相应的struts action时,则去判断struts2的文件是否有改变,当有改变发生时,就去重新加载相应的配置文件。这时就会将新修改的配置文件纳入到整个struts配置容器当中。

    在struts2中,负责重新加载配置文件的类由类ConfigurationManager的方法getConfiguration负责,此方法通过调用方法conditionalReload来实现重新加载配置文件,实现如下所示:

if (FileManager.isReloadingConfigs()) {
......
//判断是否需要重新加载
if(provider.needsReload()){
...
}
//准备重新加载所有的配置文件
if (reload) {
        ......
        packageProviders = configuration.reloadContainer(providers);
   }
}

    如上所示,所有的实现均由provider.needsReload()来确实,当发生有配置文件需要被重新加载时,就去重新加载所有配置文件。此方法一个实现为XmlConfigurationProvider,此实现如下所示:

public boolean needsReload() {

		for(String url : loadedFileUrls) {
			if(FileManager.fileNeedsReloading(url)) {
				return true;
			}
		}
		return false;
	}

    即最后,则最终取决于FileManager.fileNeedsReloading来确实,以下专门分析一下此文件如何来确定指定的url是否需要被改变。

    FileManager类中有一个内部属性files,声明如下:

private static Map<String, Revision> files = Collections.synchronizedMap(new HashMap<String, Revision>());

    其中,key表示配置文件所对应的key,如一个配置文件所对应的字符串表示(如toString),而value则为一个Revision。Revision在该类中表示一个文件的版本,此类有一个方法,标记此文件版本变化了,即需要重新加载,如下声明所示:

public boolean needsReloading() {
            return false;
        }

    对于基类,此方法自然被标明为false,表示不需要重新加载。由此类的继承类,则根据具体的实现来确实是否需要改变了。此类有两种实现,FileRevision和JarEntryRevision,两个都是根据文件的修改时间来进行判断的。具体实现如下:

    FileRevision的实现如下:

private static class FileRevision extends Revision {
        private File file;
        private long lastModified;
......
        public boolean needsReloading() {
            return this.lastModified < this.file.lastModified();
        }
}

    JarEntryRevision的实现如下:

private static class JarEntryRevision extends Revision {

        private String jarFileName;
        private String fileNameInJar;
        private long lastModified;

        public boolean needsReloading() {
            ZipEntry entry;
......
                JarFile jarFile = new JarFile(this.jarFileName);
                entry = jarFile.getEntry(this.fileNameInJar);

                return (this.lastModified < entry.getTime());
        }
}

    此几个继承类,则根据各自实现的对url或一个文件的封装来实现监控该url的变化。究竟应该创建哪个类,则由FileManager的public static InputStream loadFile(URL fileUrl, boolean openStream)方法来确定,具体实现如下:

if (URLUtil.isJBoss5Url(fileUrl)) {
                revision = JBossFileRevision.build(fileUrl);
            } else if (URLUtil.isJarURL(fileUrl)) {
                revision = JarEntryRevision.build(fileUrl);
            } else {
                revision = FileRevision.build(fileUrl);
            }
//使用默认的不需要重载的版本
            if (revision == null) {
                files.put(fileName, Revision.build(fileUrl));
            } else {
                files.put(fileName, revision);
            }

    在实现时,即通过InputStream loadFile(URL fileUrl)来读取指定的url,并返回一个文件流以便在configuration中使用。并在处理过程中,负责处理该url的版本。在取得配置信息时,判断配置文件是否有改变,则最终将由FileManager来判断所有经过此文件流的信息是否有修改了。如果有修改,则由上层的需要重新加载配置文件的配置容器自行进行处理了。

    由此可见,此类并不只应用于struts2,同样运用于其它配置框架,只要经过了此类,则就可以通过此类来判断相应的配置文件是否有改变,如果有改变了。由可以自行处理当配置文件变化了,应该怎么处理,如重新加载配置文件,以进行处理。

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/resolve-struts2-config-file-change-to-reload-for-development.html

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

邮箱地址不会被公开。 必填项已用*标注