在进行开发时,经常需要修改配置文件,而修改配置文件之后,则必须要重新启动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