欢迎来到“管理角 ”这个版,新一期的月刊专栏专注于 WebLogic 服务器的管理、配置、处理和开发方面。 开辟这个专栏的目的是为了向大家介绍在使用 WebLogic Sever 时,能普遍用到的非 J2EE 开发方面的问题。开发者和管理者同样会发现这个专栏非常有价值,因为这些文章既适用于开发又适用于最终产品的应用。此外,它很大程度上利用了来自于该领域和工程实验室的经验,它提供了对实际问题的详细解答 。
JSP预编译的必要性
本月的文章着眼于移除潜在的系统性能瓶颈,它通过解决一个最普通的问题――在服务器运行时间中的 JSP (JavaServer Page)编译的系统开销问题,这个问题困扰着几乎所有的 J2EE发展计划。虽然 JSP是在 J2EE应用范围内呈现动态 HTML视图的理想选择,但在某种程度上它们会影响性能,这比错误的更令人讨厌,给人的第一感觉是该程序很慢。
根据 J2EE规范, JSP主要是 HTML文件,在它里面包含着 Java代码用来和其他的系统组件进行交互以及动态的显示信息。规范规定所有的 J2EE编译应用服务器应当支持 JSP,客户请求一个特定的 JSP,将:
● 转换 JSP从 HTML格式成为 servlet类型的 Java类( Java源格式),用简写的 JSP符号代替完全符合规定的 Java语法
● 将新产生的 Java源文件编译成 .class字节码形式
● 在新编译的类上执行适当的接口方法并且对客户端请求返回响应。
虽然从发展的观点来看对于在表示层内管理动态 HTML的产生这是最好的途径,但它影响到服务器的运行时间环境,要求 JSP被解析、转变成 Java代码,并且在它去处理一个特定的客户端请求之前被编译。对最终用户明显的影响是,一个响应将会被延迟知道给定的 JSP文件被编译通过。考虑到一个特定的用户请求可能用到两个或多个 JSP文件,因此编译状态必需的时间增加了很多倍。
对第一个请求一个特定的 JSP 页面并且迫使被请求的文件进行初始编译的终端用户,会感觉应用程序很慢并且没有响应。 虽然这样的感觉可能存在,但是对于特定的 JSP 文件的编译过程通常在给定的应用服务器虚拟机实例的生命周期中完成一次。 因此,它对性能总体上的影响被考虑成一种障碍,而不是对应用程序总响应时间的一个严重的障碍。然而,在生产环境中为了传送基于 JSP 的 J2EE 应用程序的生产系统,必须克服 JSP 的缺陷并且对最终用户进行透明的编译。
这样 , 生产环境如何能受益于 JSP文件 , 还要避免 运行时 编译的性能打击 ? 答案是简单的 : 执行一个一般作为 JSP预编译的过程。 借用 JSP预编译,已经被预编译的在脱机环境中的 JSP文件和他们的编译结果被部署在生产环境中。如果结果类文件的预编译和部署正确的完成,应用程序服务器将会为 JSP文件运行先前的编译类,并且在运行中将不强制对特定的请求进行再编译。 这样产生了一种情况,应用程序的操作避免了多余的编译开销,允许系统管理员移除对系统总性能会造成影响的一个已知的瓶颈。
不同的方法论和途径
没有人怀疑 JSP 预编译的承诺听起来令人兴奋。 然而,为了要实现这样的承诺,你必须首先了解能够执行这个技术的不同途径,以及它们各自优点和缺点。
运行应用程序进行强制预编译
用于实现 JSP 预编译最显而易见的方法是在产品发布前,通过请求在应用程序中的所有可能的 JSP 页面,因此编译在终端用户访问站点前完成。它既可以通过第一次人工浏览整个站点时完成也可以通过从测试系列应用程序或其他脚本语言的客户端(例如 LoadRunner 或 SilkPerformer)发动自动请求来实现。 当使用这种方法(可能是所有的 JSP 预编译方法中的最简单的而又较下策的一个方法)时, 他的缺点很快就显现出来了。也许最大的缺点是很难实现跨集群环境,在集群环境中,用该方法对于单一节点的实例发送的请求依集群中的节点数量成倍的增加。而且,当这个集群是由一个或更多的 Web服务器或硬件负载权衡者来代理时,更难保证在一个集群的环境中每个服务器实例都进行 JSP预编译,因为一般没有方法来搞清代理最初把请求转到哪个应用服务器。此外,在应用服务器每次重启时,这个方法必须执行,当站点很小时,不能一次实现所有的编译就会很痛苦。因此,我们不推荐这种 JSP预编译的方法。
使用编译工具来实现预编译
因为人工执行一个站点应用程序来强制 JSP 预编译 在真实的产品环境中是一个较大的缺点 , 在预编译运行期间选择编译 JSP ,使其变成为 servlets变得更令人心动。 幸运地, WLS 提供了二个方法。第一种方法在服务器启动部署一个特定的 Web 应用程序的时候执行预编译( declarative 预编译),第二种方法是命令行 Java 工具( weblogic.jspc )允许过程在完全脱机的情况下处理( 程序方式的 预编译)。两种方法都有它们的优点, 程序方式的 预编译在两者中有更灵活的选项,并且提供更让人无法抗拒的理由来使用它。
DECLARATIVE 预编译
对于在 WLS下公布的预编译,一个特定的 Web应用程序(独立的或者作为 EAR的一部分)能够被配置,因此所有的 JSP在应用程序部署(服务器启动时)和重新部署(运行时)期间里被预编译。对 WEB-INF/ weblogic.xml部署描述符要做必要的配置变化,使用预编译 <jsp-param/>指令,如下:
<weblogic-web-app>
…
<jsp-descriptor>
<jsp-param>
<param-name>precompile</param-name>
<param-value>true</param-value>
</jsp-param>
</jsp-descriptor>
…
</weblogic-web-app>
在一个特定的 Web 应用程序上进行部署(或重新部署),如果上述的参数被设定成真, WLS 将会在 WAR 内尝试预编译所有的 JSP 文件,在程序中从 Web 应用程序的根目录下循环的运行它的方法 ( 略过 Web-INF) 。以 . jsp 或 .JSP 为扩展名的文件都变成了编译的对象。 被编译后的文件被以适当的包目录结构形式被放置在 Web 应用程序的临时工作目录下面(默认在 Web-INF 子目录中,除非在 weblogic.xml 里有特别说明)。
这个方法是到目前为止进行 JSP预编译最方便的途径( “flick-a-switch” 途径 ),他 有许多指出来毫无意义的缺点。如果一个错误在 JSP的编译期间或在部署 (或重新部署 ) 的时候发生, Web 应用程序的预编译将会在例外处暂停。另外,如果在一个特定的 Web应用程序里面有许多 JSP文件的情况, declarative预编译显著的影响着部署时间,阻断部署直到所有的文件都被编译。对于大型的应用程序,当出现数以百计的 JSP 文件以 declarative预编译被执行的时候,这种部署时间趋向以分钟来计算 (在某些情况 10到 15分钟,其他情况可能更长时间 )。设想开始一个服务器实例,在一个特定的 Web应用程序周期内进入部署状态用 declarative 预编译激活。如果在应用内有很多的 JSP文件以及部署,接近完成时就已经花费了大量的时间,在编译期间由于抛出一个例外而突然失败,当然会引起挫折感。虽然起先看起来比较方便,但 declarative 编译对生产系统管理造成重大的风险,因此应该在经过慎重的考虑后再使用它。
程序方式的预编译
在 WLS 下最 可靠的预编译 JSP 的方法是使用 Java 命令行 , weblogic.jspc ,它位于 WLS 安装的 lib 目录之下的 weblogic.jar 文件中。这个工具允许开发者在发展阶段和在部署前解决编译时间问题的时候编译需要的 JSP 文件。它也为生产系统提供一个有能力实现 JSP 预编译的管理员。这种用法的主要好处是:
● 文件可以被预编译一次然后可以被多次部署。( 这不被服务器实例的重复利用所影响 )
● 编译时的例外可以被预先解决而不影响部署。
● 类可以通过集群部署。
使用 weblogic.jspc 的缺点是需要人工干涉,并且它在开发时并当在 JSP 文件变得过时的时候必须被重新运行。然而,考虑到前面的两个方法的讨论, 我们几乎不能将这种不方便当成该方法的一个缺点,因此推荐它作为最可靠和最灵活的机制来实现 JSP 预编译。
执行 weblogic.jspc
为了更有效的使用 weblogic.jspc ,你必须首先了解它的用法和语法。这篇文章我们将利用 WLS6.1 SP2 的工具的功能。注意:下面给出的语法和最好的惯例应该应用于 WLS 6.1 的所有版本以及新的 WLS 7.0 。
为了调用命令行 JSP编译器( weblogic.jspc ),你必须确定下面的内容:
● PATH环境变量必须包含你机器上安装的 J2SE1.3包的二进制目录(例如, /opt/j2se/1.3.1/sdk/bin 或者 c:\sunsoft\j2se\1.3.1\sdk\bin),以获得 JVM运行时的支持。如果你打算使用 javac作为你的 JSP编译的 Java编译器,要确定 PATH包含全部 Java 1.3 的软件开发工具包( SDK)的二进制目录,并且不仅仅是 JRE( Java Runtime Engine, Java运行时间引擎),因为没有编译器和 JRE关联。 如果你打算使用一个编译器而不是 javac(例如 Jikes),也要为那个编译器确定在 PATH中包含正确的目录。
● 设置 Java系统类路径用来包含来自 WLS 6.1 SP2 安装目录的 weblogic.jar文件,通过在产品库目录下默认建立(例如, /opt/bea/wlserver6.1/lib/weblogic.jar或者 c:\bea\wlserv -er6.1\lib\weblogic.jar)。此外,请确定在 JSP编译阶段中你可能需要的参考类( JAR或类文件)也在你的类路径中。
在第一次执行 weblogic.jspc之前,你需要测试你的命令行配置是否是按上述配置。它可以通过简单运行一个 WLS版本检查来完成,使用命令“ java weblogic.version”,这个命令应该返回下面的内容:
which should return the following:
WebLogic Server 6.1 SP2 12/18/2001 11:13:46
#154529
WebLogic XML Module 6.1 SP2 12/18/2001
11:28:02 #154529
如果你的输出和上面的不相似(和你运行的版本相对应),在进行 JSP预编译前,要重新访问 PATH和类路径变量将其设置成你的当前命令行环境。
一般的 weblogic.jspc的语法如下面给出的:
java weblogic.jspc [options] <jsp files>...
在一个编译器的单一调用中默认情况下 JSP编译器可以编译一个 JSP文件或一组 JSP文件,并且可以通过设置命令行选项,编译器可以以不同的方法工作。下面给出一个例子:
java
weblogic.jspc
-webapp mywebapp
-compiler javac
-compileFlags "-g"
-classpath /u/apps/dist/src/lib.jar
-d .
-package com.slackwerks.mywebapp.jsp
-commentary
-keepgenerated
-k
mywebapp\index.jsp
这篇文章只列举了一个例子,如果你要想更加了解 weblogic.jspc如何能在你的环境中使用和管理的话,请参阅 www.slackwerks.com/wldj,我们提供了对整套的工作选项,使用的含义以及相关联问题的讨论。
结论
虽然关于 JSP 预编译 的问题较多,但许多的途径可以解决。然而 ,考虑到上文所说的那些优点 和缺点 ,应该较容易的看出经由 weblogic.jspc预编译的程序方式是为克服 JSP 固有的缺点的一个灵活的选项。在开发阶段的早期,熟悉该工具将改善生产期间应用程序的管理和性能状况。