在我们的 Web 应用程序中,由于类加载,某些页面的第一次加载需要花费少量但值得注意的额外时间。有没有人有任何聪明的方法在启动时在 JVM 中预加载 Web 应用程序类?
更新:我们现在要做的是在 db 表中存储一堆(700)完整的类名。我们在启动时读取表格并执行 Class.forName()。它工作正常,但我认为可能有更聪明的方法。我们使用分析器确定了启动时引用的 700 个类。
在我们的 Web 应用程序中,由于类加载,某些页面的第一次加载需要花费少量但值得注意的额外时间。有没有人有任何聪明的方法在启动时在 JVM 中预加载 Web 应用程序类?
更新:我们现在要做的是在 db 表中存储一堆(700)完整的类名。我们在启动时读取表格并执行 Class.forName()。它工作正常,但我认为可能有更聪明的方法。我们使用分析器确定了启动时引用的 700 个类。
您可以尝试在单个虚拟类中编写静态初始化程序代码,然后在启动时加载该类。它的静态初始化器将创建一些关键对象,这些对象会导致加载其他类(您可以递归地执行此操作以提高代码模块化)。我敢打赌,这会更短更简单(而且您无需担心数据库问题)。
更好的方法可能是编写一个 servlet,它在启动时会遇到一些加载缓慢的页面并丢弃结果。这会强制加载类。多次加载这些页面将增加完成的即时编译量(加速您的代码并减少 JIT 编译成本)。还有其他优点:这是一种“开机自检”,它会导致一次性启动任务完成,并且它还可以在一定程度上启动各种缓存。
load-on-startup
好吧,它不是很聪明,因为它是规范的一部分,但是您可以通过将元素添加到 servlet 定义中来让您的 servlet 在 Web 应用程序启动时启动web.xml
:
<servlet>
<description>....</description>
<display-name>....</display-name>
<servlet-name>....</servlet-name>
<servlet-class>....t</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
如果您为一组有代表性的服务执行此操作——或者可能只是一个可以预加载所需所有内容的 servlet——那么您将实现您的目标。
如果这还不够,例如,如果您想从 JAR 文件中加载类,而不是以有意义的方式实际初始化它们,并且如果您知道您的 JAR 文件在哪里或者可以找出您的 JAR 文件在哪里,那么您可以使用类似于此 JCP 论坛帖子“列出包中的类”或该线程中的一些后续帖子中的代码。从类列表中,您可以获取 Class 对象,这将有助于加载类而无需实际实例化实例。
线程内的 Class.forName 可能会加快速度。从第一页上可能被点击的那些开始。
线程化它应该使启动更快(它会更早返回),并且由于您首先开始加载更有可能的类,因此它们有望在页面被点击时被加载。对于其他相同的交易,希望在页面被点击之前加载。
您还可以更进一步并为每组类启动一个线程(给定页面上需要的那些类将是一个组)。这可能会加快速度,因为您可以并行化从磁盘读取(但这也可能会减慢速度)。
这并不能保证在第一次加载页面时速度不会变慢,但值得研究。
Class.forName() 是我唯一能想到的。我当然有兴趣听到更聪明的选择。
另一种选择是选择一组 URL 并在启动时运行脚本来访问这些 URL。
也许您可以尝试将 700 个类转换为 jar 文件并应用一些方法进行预加载,可能是将 jar 放在引导类路径中(我不确定它是否有效..但只是给出一个提示)。
您始终可以使用第三方 jsp 编译器(例如 Jasper)在部署 JSP 页面之前对其进行预编译。