最近遇到一个问题: 环境中的JSP页面在被修改以后没有在浏览器中表现出来, 呈现出的仍然是旧版的样子。
这个事情比较奇怪,但凡有初级web 开发经验的人都了解,在web容器是tomcat的开发环境中修改jsp页面后无需重启tomcat,仅仅刷新就可以在浏览器中看到效果,这已经是一个人尽皆知的事情了,那这个幺蛾子是怎么飞出来的?
本着生活问度娘,技术求谷哥的精神,遂google之,原理还是挺有意思的:
1. JSP怎么工作
这个不多说了,跟我们问题关键的一点就是JSP使用时会被容器编译成java的编译后文件:.class文件,而后使用的都是这个.class文件。这个文件的路径在tomcat中是:
%catalina_home%\work\Catalina\localhost\\org...
这里就有一个问题了,既然JSP需要被编译成.class文件才能使用(区别于解释性的脚本语言),那么要实现“仅仅刷新就能生效”的目的必然要求有人去编译它,这个忙人是谁呢:tomcat ?
2. Tomcat 对JSP的预编译机制
确实是Tomcat, 它的基本预编译规则是:当接到一个对某JSP 页面的请求时,检查该JSP页面与之前由该JSP页面编译出的.class文件的时间戳,如果JSP页面较新,那么重新编译,并覆盖老的.class文件,否则仍使用之前的.class文件,并不进行再次编译。
事情说得这,遇到的问题已经找到原因了,是时间戳引发的问题。
本着除恶务尽的原则,继续研究了下,发现:
a. “仅仅刷新就能生效” 只有在tomcat 的development 模式下才能生效,在生产模式下是无法生效的。Tomcat默认使用development模式,可以再文件:Tomcat\conf\web.xml中把developmen t的值改为false来切换到生产模式。
b. 生产模式不检查JSP页面的时间戳,来进行recompile,所以JSP文件被修改后只有通过重启tomcat才能生效。这样做的原因是每次去check时间戳会耗费较多的性能,所以建议在产品出厂时都设置为product模式。
c. 在生产模式下可以通过配置一个参数:checkInterval 来驱使tomcat 没过一段时间去check JSP页面的时间戳进行recompile, 虽有一定的延迟性但是也能达到“仅仅刷新就能生效”, 但如果这个interval比较小,那仍对性能有拖累。这种情形有个特点有别于之前: 这种recompile被称之为:“background compile”, 意识是说并不阻塞请求,只是触发recompile,在recompile完成之前仍然使用旧版本,在完成之后才使用新版本
d. Development 模式中,对JSP页面的check频率也可以通过一个参数进行调节:modificationTestInterval。 比如说modificationTestInterval = 10s, 即是说在对某个JSP页面进行时间戳检查后的10s内,即便再有对该JSP页面的请求也不进行时间戳检查,当然也不会触发recompile。如果modificationTestInterval = 0,那么每次都会检查时间戳。这个参数的默认值是4s。
e. 还有一种情形无法recompile: 一个JSP页面作为子页面被另外一个JSP页面include, 如果子页面发生了改变但是父页面没有,不会recompile(已经在tomcat7 中修改)
最后还有一个问题,自动编译完成以后,tomcat是如何自动加载这些.class呢,好在这是另外一个问题了。
阅读(365) | 评论(0) | 转发(0) |