附录1  DQM容器介绍

 

F1.1 编译动态文件

F1-1-1

 

DQM容器类似于JSP容器,其主要作用就是用于执行动态文件(默认扩展名.dqm),因为是编译后执行,所以理所当然第一步是如何先编译动态文件。那么如何编译呢?因为动态文件是在html语言中嵌入dqm脚本语言所以编译的第一步是将动态文件转换成标准的java文件,转换后的java文件将保存在当前主机或虚拟主机的web根目录下的WEB-INF\work\com\kangaroo_egg\workfile目录中。当前主机或虚拟主机的web根目录请参见2.42.5节的webPath项。第二步是将刚才已经转换且保存的java文件编译成class文件,编译后的class文件保存在与java文件的同一目录下。编译后的class就可以被java虚拟机执行了。介绍了编译动态文件过程,那么服务器会在什么时候编译动态文件呢?在下一节介绍流程中就会有所介绍。

 

 

F1.2 DQM容器流程

F1-2-1

 

当用户访问一个动态文件时DQM容器首先去检查“动态可执行文件缓存池”中是否已有相对应的实例,如果有的话则检查实例是否与其对应的动态文件一致,如果一致的就执行实例返回结果,如果不一致(比如动态文件已经修改了,而实例是动态文件修改前的)则如上一节所说的进行编译动态文件,再将编译后的class文件初始化实例放入“动态可执行文件缓存池”中执行返回结果。

“动态可执行文件缓存池”中如没有动态文件相对应的实例的话则判断此动态文件是否已经被编译过(相对应的目录中存在已编译过的class文件),如果编译过则检查已编译的class文件是否与其对应的动态文件一致,如果一致则将已编译的class文件初始化实例放入“缓存池”中执行返回结果,如果不一致则进行编译而后初始化实例放入“缓存池”执行返回结果。如果动态文件没有被编译过(相对应目录中不存在已编译的class文件)则进行编译而后初始化实例放入“缓存池”执行返回结果。

 

注意:通常情况下如果修改了动态文件,DQM容器会重新编译动态文件,并把编译生成的新class文件覆盖WEB-INF\work\com\kangaroo_egg\workfile目录下原来的旧文件。在少数情况下更新动态文件后还是看到旧的内容,请删除work目录下相关的文件,这样能够确保重新编译。

 

 

F1.3 关闭自动编译时DQM容器流程

  webconfig.xml中主机和虚拟主机有一个配置项autoCompile(参见2.42.5节),此项主要用于是否允许服务器自动编译动态可执行文件。为什么需要这个功能呢?一个原因是编译动态文件很占用系统资源,所以在正式运行的服务器上可以禁止对动态文件编译,用户可以在本地计算机预先编译好后再将编译后的class文件上传至服务器相应目录(web根目录下的WEB-INF\work\com\kangaroo_egg\workfile目录中)。另一个原因是如果开启了自动编译则服务器就会监视动态文件有无修改,如果修改了则先前编译的class文件就与修改后的动态文件不一致了,所以必须重新编译,在开发阶段这是合理的,因为要不断修改动态文件且查看修改后结果,但是在运行阶段动态文件很少或者几乎不改变,于是就无需消耗资源监视动态文件是否改变从而重新编译。我们来看一下关闭自动编译后的流程,您可以与未关闭前的流程做比较。

F1-3-1

 

从流程图中看出此时当用户访问一个动态文件时,DQM容器首先去检查“动态可执行文件缓存池”中是否已有相对应的实例,如果有的则不会再检查实例是否与其对应的动态文件一致而直接执行“缓存池”中实例且返回结果。

如“动态可执行文件缓存池”中没有动态文件相对应实例的话,则判断此动态文件是否已经被编译过(即相对应的目录中存在已编译过的class文件),如果编译过则不会再检查已编译的class文件是否与其对应的动态文件一致,而是直接将已编译的class文件初始化实例后放入“缓存池”中执行返回结果。

如果动态文件没有被编译过(即相对应的目录中不存在已编译的class文件)则报500.2错误,提示所访问的动态文件需要编译后才能执行,而目前服务器禁止编译。

细心的读者在看完上面的流程后可能会有二个疑惑,首先只要“动态可执行文件缓存池”中有相对应的实例则直接执行而不管实例是否与其对应的动态文件一致,那么即使修改了动态文件和动态文件对应的class文件,而“缓存池”中含有相对应的实例还是旧的,不过即使“缓存池”中实例是旧的过期的可是还是会直接执行,那么岂不是修改后的动态文件永远不会被执行?可是有时候我们还是会对已运行web应用进行一些小的修改,那么在关闭了自动编译的这时候该怎么办呢?其实无非就是将“缓存池”中的这个实例清除,只要重启服务器则“缓存池”中的所有实例就清除了,不过运行中的服务器是不太易于重新启动的,而且重启后“缓存池”中的实例都没有了,那些原本就无需改动的动态文件也必须重新实例化放入缓存池中,因此增加了无谓的开销。于是有更好的方法便是前面10.3节提到过的。

首先将修改后的动态文件和编译后的文件覆盖原文件(编译后的文件在web根目录下的WEB-INF\work\com\kangaroo_egg\workfile目录中),然后用10.3节的方法将“动态可执行文件缓存池”中此动态文件实例删除,这样的话当再次访问此动态文件时服务器会发现“缓存池”中没有相对应实例,于是判断此动态文件是否已经被编译过,因为我们刚才已经将重新编译的文件覆盖了原来的,所以服务器发现动态文件已编译且将编译后的class文件初始化放入“缓存池”中执行返回结果,而此时载入的就是已经重新编译过的class文件了,于是就会返回修改后的结果。其实最主要是覆盖编译后的class文件,而修改后的动态文件覆不覆盖原文件是无所谓的,为什么呢?前面流程中已经介绍过了当初始化class文件时不会检测class文件是否与其对应的动态文件一致,而是直接将已编译的class文件初始化实例后放入“缓存池”中执行返回结果。所以只要已编译的class文件修改了就可以了。不过为了一致还是最好同时覆盖动态文件。

如果要清除类缓存也请参阅前面10.4节。

另外一个疑惑是用户访问的动态文件对应的实例在“缓存池”中不存在,同时此动态文件也没有编译过(即此动态文件编译后的class文件不存在),则服务器会报500.2错误,为什么会报这个错误呢?因为此时自动编译功能关闭,所以在既无缓存实例又无编译过的动态文件时当然无法执行,那么此时该怎么做呢?只要先在其它机器上用打开自动编译的kangaroo-egg服务器编译(F3.1节也介绍了编译工具用于编译动态文件),然后将编译后的文件上传至那台关闭自动编译的服务器上,这样再次访问此动态文件时DQM容器就会将编译后的class初始化放入缓存池执行。至于编译后的class文件存放目录在web根目录下的WEB-INF\work\com\kangaroo_egg\workfile目录中。