级别: 初级 Scott Johnson (scottjoh@us.ibm.com), IBM WebSphere Application Server Development, IBM
2004 年 5 月 01 日 在生产服务器环境和开发环境中,可以配置 WebSphere Application Server Technology for Developers (TD) V6 中的 JavaServer Pages(JSP)引擎来优化性能。本文是一个分为三部分的系列文章的第二部分,它探讨了在 WebSphere Application Server V6 TD JSP Engine 中可用的与性能相关的配置选项。
在生产服务器环境和开发环境中,可以配置 WebSphere Application Server Technology for Developers (TD) V6 中的 JavaServer Pages(JSP)引擎来优化性能。本文是一个分为三部分的系列文章的第二部分,它探讨了在 WebSphere Application Server V6 TD JSP Engine 中可用的与性能相关的配置选项。
引言
这篇关于 WebSphere Application Server Technology for Developers(TD)V6 中的 JavaServer Pages(JSP)的文章系列的
第一部分描述了内部操作、配置参数以及批处理编译器的处理过程,展示了在预部署的应用程序中对 JSP 进行批处理编译如何简化部署过程以及提高运行时性能。第 2 部分把重点放在性能方面。在这篇文章中,我们将会详细讨论 IBM WebSphere Application Server V6 TD 中的 JSP Engine 可用的性能调优选项,它可以用于配置产品以及开发环境,以达到最优的性能。
JSP Engine 配置参数
许多配置参数可用于 WebSphere Application Server 6.0 TD 中的 JSP Engine。表 1 列出了所有这些参数。在本文中,我们将会集中讨论与性能相关的参数。这些参数(在表 1 中用黑体显示)是:
- reloadEnabled
- reloadInterval
- disableJspRuntimeCompilation
- trackDependencies
- useThreadTagPool
- usePageTagPool
- keepgenerated
- useJikes.
表 1. JSP Engine 配置参数
|
参数名
|
描述
|
值
|
缺省值
| | compileWithAssert | 指定是否在生成的 Java® 类中包含对 JDK 1.4 断言功能的支持。如果为 true,则
-source 1.4 选项将被传递给 Java 编译器。
| true 或 false | false | | classdebuginfo | 指示编译器是否应该包含生成的类文件中的调试信息。如果设置为 true,则
-g 选项将传递给 Java 编译器。
| true 或 false | false | | deprecation | 指示编译器在编译生成的 Java 源代码时是否应该产生不赞成(deprecation)警告。如果设置为 true,则
-deprecation 选项将传递给 Java 编译器。
| true 或 false | false | |
disableJspRuntimeCompilation
| 如果这一选项设置为 true,则 JSP Engine 在运行时将不会转换和编译 JSP 文件;JSP Engine 将只加载预先编译的类文件。无需呈现 JSP 源文件以加载类文件。如果该选项设置为 true,则应用程序可以在没有 JSP 源文件的情况下安装,但它必须有预先编译的类文件。有一个同名的 Web 容器自定义特性可以用于确定安装在服务器中的所有 Web模块的行为。如果 Web 容器自定义特性和 JSP Engine 选项都设置了,那么 JSP Engine 选项优先。 | true 或 false | false | | extendedDocumentRoot | 为了使得 JSP 资源可以跨 Web 应用程序档案文件共享,请指定用逗号界定的目录和/或 JAR 文件列表作为搜索路径,这样,如果在 Web 应用程序档案文件的公共文档树中不能定位所请求的源文件,就能够使用这些搜索路径了。(如果 JSP 位于 JAR 文件中,则当 reloadEnabled 为 true 时,为了重新编译的目的 JAR 文件的时间戳将会用于 isOutDated 检查。) | 用逗号界定的目录和/或JAR 文件列表 | null | | ieClassID | 指示用于 Internet Explorer 的 Java 插件 COM 类的 ID。
<jsp:plugin> 标记使用这个值。
| classid |
clsid:8AD9C840-044E-11D1-B3E9-00805F499D93
| | jsp.file.extensions | 对于带有四个标准的扩展名(请参见缺省值)以外的扩展名的 JSP 文件,可以用这个参数来配置该扩展名。这些扩展名将添加到标准的扩展名中。
(添加扩展名的首选方法是在
web.xml 中创建
<jsp-property-group> ,并给每个扩展名添加一个
<url-pattern> 标记。)
| JSP Engine 应该处理的用冒号或分号定界的文件扩展名列表。格式如下:
*.ext1; *.ext2: *.extn...
| 由 JSP Engine 处理的标准扩展名如下:
*.jsp
*.jspx
*.jsw
*.jsv
| |
keepgenerated
| 指示在处理的转换阶段由 JSP 编译器生成的 Java 文件是否应该保留。 | true 或 false | false | | keepGeneratedclassfiles | 指示在处理的转换阶段由 JSP 编译器生成的类文件是否应该保留。 | true 或 false | true | |
reloadEnabled
| 决定如果修改 JSP 文件及其依赖性(请参见
trackdependencies),是否将在运行时转换和编译JSP 文件。如果设置为 false,除非disableJspRuntimeCompilation 参数设置为 true,否则在必要时(在第一次请求 JSP 时)仍会编译 JSP。
| true 或 false | false | |
reloadInterval
| 如果启用重新加载,这一参数决定从请求 JSP 到引擎开始检查重新加载是否有必要这之间引擎要等待多少秒钟的时间。 | 秒的整数 | 5 | | scratchdir | 指定创建生成的类文件的目录。
(可以按照服务器范围使用系统特性
com.ibm.websphere.servlet.temp.dir 来设置 scratchdir选项。JSP Engine scratchdir 参数优先于系统特性
com.ibm.websphere.servlet.temp.dir )
| 指向scratchdir 目录的完整路径 |
[WAS_INSTALL_ROOT]/temp
| |
trackDependencies
| 如果启用重新加载,这一参数决定 JSP Engine 是否跟踪对所请求的 JSP 的依赖性以及 JSP 本身的修改。JSP Engine 所跟踪的依赖性有三个类型:
- 在该 JSP 中静态包含的文件。
- 该 JSP 所引用的标记文件。(不包括 JAR 中的标记文件)
- 该 JSP 所引用的标记库描述符(TLD)(不包括 JAR 中的 TLD).
| true 或 false | false | | useImplicitTagLibs | JSP Engine 隐式地将
tsx 和
jsx 识别为引擎所提供的标记库的标记库前缀。如果
tsx 和/或
jsx 用作用户的标记库的前缀,那么用户的标记库将覆盖隐式的标记库。然而,隐式的标记库将由 JSP Engine 缓存。显式地将这一参数设置为 false 会告诉引擎不要缓存这个隐式的标记库并保存源文件。
| true或 false | true | |
useJikes
| 指定 Jikes 是否应该用于编译 Java 源文件。(Jikes 不是 WebSphere Application Server 附带的。) | true 或 false | false | |
usePageTagPool
| 基于单个 JavaServer Page 启用或禁用自定义标记处理程序的重用。* | true 或 false | false | |
useThreadTagPool
| 基于单个每个请求线程启用或禁用自定义标记处理程序的重用。* | true 或 false | false | | verbose | 指示编译器在编译生成的 Java 源代码时是否应该生成详细的输出。将这一参数设置为 true 会将
-verbose 选项传递给 Java 编译器。
| true 或 false | false |
* 启用自定义标记处理程序重用可能会在与重用的标记功能有关的标记处理程序代码中出现问题。自定义标记处理程序应该始终做两件事:
- 标记处理程序的 release() 方法必须使它的状态复位,并且释放它可能已经使用的私有资源。JSP Engine 确保在标记处理程序被作为垃圾回收之前调用 release() 方法。
- 在 doEndTag() 方法中,所有与实例相关的实例状态必须复位。
配置 JSP Engine 参数的方法
WebSphere Application Server 不支持通过管理控制台或管理脚本来修改部署描述符扩展参数。然而,您将需要能够这样做,因此,在这一部分中,我们将描述一种添加、改变或删除 JSP Engine 配置参数的方法。
JSP Engine 配置参数存储在 Web 模块的配置目录的
WEB-INF/ibm-web-ext.xmi 文件中。下面是一个配置目录的示例:
{WAS_ROOT}/config/cells/cellname/applications/enterpriseappname/deployments/deployedname/webmodulename
如果应用程序部署在 WebSphere Application Server 中,并且将 Use Binary Configuration 标志设置为 true,那么
WEB-INF/ibm-web-ext.xmi 文件将会在 Web 模块的二进制目录中,而不是在配置目录中。下面是一个二进制目录的示例:
{WAS_ROOT}/installedApps/nodename/EnterpriseAppName/WebModuleName/
WEB-INF/ibm-web-ext.xmi 中的 JSP Engine 配置参数条目可能像看起来像是这样的:
<jspAttributes xmi:id="JSPAttribute_6"name "keepgenerated" value="true"/>
清单 1 展示了一个样本
ibm-web-ext.xmi 文件。粗体部分代表 JSP Engine 配置参数。
清单 1. 样本 ibm-web-ext.xmi 文件
<?xml version="1.0" encoding="UTF-8"?>
<webappext:WebAppExtension xmi:version="2.0" xmlns:xmi=http://www.omg.org/XMI
xmlns:webappext="webappext.xmi" xmlns:webapplication="webapplication.xmi" xmi:id="WebAppExtension_1"
reloadInterval="9" reloadingEnabled="true" defaultErrorPage="error.jsp" additionalClassPath=""
fileServingEnabled="true" directoryBrowsingEnabled="false" serveServletsByClassnameEnabled="true"
autoRequestEncoding="true" autoResponseEncoding="false">
<webApp href="WEB-INF/web.xml#WebApp_1"/>
<jspAttributes xmi:id="JSPAttribute_1" name="useThreadTagPool" value="true"/>
<jspAttributes xmi:id="JSPAttribute_2" name="verbose" value="false"/>
<jspAttributes xmi:id="JSPAttribute_3" name="deprecation" value="false"/>
<jspAttributes xmi:id="JSPAttribute_4" name="reloadEnabled" value="true"/>
<jspAttributes xmi:id="JSPAttribute_5" name="reloadInterval" value="5"/>
<jspAttributes xmi:id="JSPAttribute_6" name="keepgenerated" value="true"/>
<!-- <jspAttributes xmi:id="JSPAttribute_7" name="trackDependencies" value="true"/> -->
</webappext:WebAppExtension>
|
要添加一个 JSP Engine 配置参数,您需要执行以下步骤:
- 打开该文件以供编辑。
- 按照清单 1 中的示例,添加一行参数行,然后设置参数和期望值。请注意:
JSPattribute_n 中的整数
n 在文件中应该是惟一的。
- 保存文件并重启服务器,使参数生效。
要删除一个配置参数,您需要执行以下步骤:
- 打开该文件以供编辑。
- 完全删除需要删除的行,或者通过用标准删除标记包括该行来将其注释掉(如清单 1 中 trackDependencies 属性行所示)
- 保存文件并重启服务器。
在清单 1 中,
WebAppExtension_1 包含
reloadInterval="9" reloadingEnabled="true" 。在 WebSphere Application Server V5 中,这些属性控制了 servlet 和 JSP 的重新加载。然而,在 WebSphere Application Server V6 TD 中,它们却没有控制 JSP 的重新加载。
配置 JSP 的重新加载
正确配置特殊环境下的 JSP 的重新加载对于 JSP Engine 的性能是很关键的,不管它是用于生产还是用于开发。表 2 显示了相关参数的推荐配置。
表 2.生产和开发环境的重新加载推荐设置
|
推荐设置
| |
配置属性
|
生产环境
|
开发环境
| | reloadEnabled | false | true | | reloadInterval | n/a
(如果 reloadEnabled 为 false 则忽略)
| ~5 秒 | | trackDependencies | n/a
(如果 reloadEnabled 为 false 则忽略)
| true
另一种选择是,如果依赖性没有改变,则把它设置为 false 以便缩短响应时间。
| | disableJspRuntimeCompilation | true
另一种选择是,如果 JSP 没有预先编译,则把它设置为 false,这样在第一次请求时就需要对它进行编译。
| false |
JSP 重新加载
JSP 重新加载是通过 reloadEnabled 参数来激活的:
<jspAttributes xmi:id="JSPAttribute_1" name="reloadEnabled" value="true"/>
reloadEnabled 属性决定,如果修改 JSP 文件或它的依赖性,则当 trackDependencies 设置为 true 时是否要在运行时转换和编译该JSP 文件。如果 reloadEnabled 设置为 false,则除非 disableJspRuntimeCompilation 参数为设置 true,否则在必要时(在 JSP第一次被请求时)仍然需要对它进行编译。举例来说,如果一个类文件比它的 JSP 源文件旧,则即使 reloadEnabled 设置为 false,该 JSP 在第一次被请求时都会被编译。在随后的请求中,除非 reloadEnabled 设置为 true,否则即使 JSP 源文件被修改或者类文件被删除,它也不会再被编译了。
重新加载时间间隔
重新加载的时间间隔是通过 reloadInterval 参数来设置的:
<jspAttributes xmi:id="JSPAttribute_1" name="reloadInterval" value="5"/>
如果启用了重新加载,reloadInterval 将决定从 JSP 被请求到引擎开始检查重新加载是否有必要这之间引擎要等待多少秒钟的时间。一旦 reloadInterval 超时,就会执行重新加载检查程序并将重新加载时间间隔定时器设置为 0。
让我们举一个 reloadInterval 设置为 10 的例子。这个重新加载时间间隔会独立地应用到每个 JSP 中,这表明修改后的 JSP 的重新加载不会都发生在同一时间。在一个给定的 JSP 被请求以后,JSP Engine 会等待 10 秒才去检查对这个 JSP 的下一个请求,以查看该 JSP 是否已被修改以及是否需要重新加载。一旦这个检查执行了(不管 JSP 是否真的需要重新加载),将会再等待 10 秒才对该 JSP 进行下一个检查。既然 JSP 是在不同的时间被请求的,10 秒的时间间隔就会相互错开。下面是一个简化的示例:
- 在 10:00
jsp1.jsp 第一次被请求并被执行。
- 从 10:00 到 10:00:10,
jsp1.jsp 被请求了 3 次。对于这些请求引擎都不会进行重新加载检查。
-
jsp1.jsp 下一次被请求是在 10:00:15。10 秒的 reloadInterval 已经超时了 5 秒,所以 JSP Engine 检查
jsp1.jsp ,看它是否需要重新加载,如果需要,则重新加载它。
- 在 10:02
jsp55.jsp 第一次被请求并被执行。
- 从 10:02 到 10:02:12,
jsp55.jsp 被请求了 2 次。对于这些请求引擎都不会进行重新加载检查。
-
jsp55.jsp 下一次被请求是在 10:00:37。10 秒的 reloadInterval 已经超时了 25 秒,所以 JSP Engine 检查
jsp55.jsp ,看它是否需要重新加载,如果需要,则重新加载它。在 10:00:37
jsp55.jsp 的 reloadInterval 定时器启动计数。
如果重新加载时间间隔为 0 并且
reloadEnabled=true ,那么 JSP Engine 在每次对 JSP 请求时都会检查是否需要重新加载。
依赖性跟踪
依赖性跟踪是通过 trackDependencies 参数来设置的:
<jspAttributes xmi:id="JSPAttribute_1" name="trackDependencies" value="true"/>
如果启用了重新加载,trackDependencies 将决定 JSP Engine 是否跟踪对请求的 JSP 的依赖性以及 JSP 本身的修改。JSP Engine 所跟踪的依赖性有三种类型:
- 在该 JSP 中静态包括的文件。
- 该 JSP 所引用的标记文件。(不包括 JAR 中的标记文件)。
- 该 JSP 所引用的 TLD(不包括 JAR 中的 TLD)。
依赖性跟踪的一个示例:
-
toplevel.jsp 中静态包括
footer.jspf 。
- 当
toplevel.jsp 编译时,trackDependencies 设置为 true。
- 指向
footer.jspf 的路径以及
footer.jspf 的时间戳存储在为
toplevel.jsp 生成的类文件中。
-
footer.jspf 随后被修改。
-
footer.jspf 被请求,同时它的重新加载时间间隔已超时。
- JSP Engine 将对存储在类文件中的时间戳和磁盘中的
footer.jspf 的时间戳进行比较。如果时间戳不同,就编译
toplevel.jsp ,并将修改信息摘录给
footer.jspf 。
- JSP 编译时 trackDependencies 应该为 true,以便依赖性跟踪能够工作。如果 JSP 编译时 trackDependencies 为 false,那么它的类文件将不包括任何的依赖性信息。同样,由于依赖性的时间戳存储在一个 JSP 类文件中,所以即使在服务器不运行时对依赖性做了修改,依赖性跟踪照样工作。
禁用编译
禁用 JSP 运行时编译是通过 disableJspRuntimeCompilation 参数来设置的:
<jspAttributes xmi:id="JSPAttribute_1" name="disableJspRuntimeCompilation" value="true"/>
如果 disableJspRuntimeCompilation 设置为 true,则 JSP Engine 在运行时不会转换和编译 JSP 文件;JSP Engine 只会加载预先编译的类文件。无需呈现 JSP 源文件来加载类文件。该选项为 true 时,应用程序可在没有 JSP 源文件的情况下安装,但它必须拥有预先编译的类文件。有一个同名的 Web 容器自定义特性,它可以用于确定安装在服务器上的所有 Web 模块的行为。如果 Web 容器自定义特性和 JSP Engine 选项都设置了,那么 JSP Engine 选项优先。
图 1 显示了 trackDependencies 为 false 时与 JSP 的重新加载有关的处理顺序。图 2 显示了 trackDependencies 为 true 时所执行的其他处理。您可以看到 disableJspRuntimeCompilation 为 true 时所采用的路径很明显是最为有效的。
图 1.trackDependencies 为 false 时的重新加载处理顺序
当 trackDependencies 为 true 时,JSP Engine 执行其他的文件系统访问来确定自从 JSP 的上一次转换和编译以后,JSP 的依赖性是否发生变化。图 2 显示了这些其他处理,处理流程以“Is JSP classfile outdated?”判决菱形的“No”路径来表示。
图 2.trackDependencies 为 true 时执行的其他重新加载处理
池化经典标记处理程序
标记处理程序的池化只对经典标记处理程序可用;JSP 2.0 规范并不允许池化简单标记处理程序。在 WebSphere Application Server V6 TD 中,有两类经典标记处理程序池可用:
- 页面级池:由 usePageTagPool 参数配置。
- 线程级池:由 useThreadTagPool 参数配置。
如果 usePageTagPool 和 useThreadTagPool 都设置为 true,则使用的是基于页面的标记池。
当 JSP 中使用自定义操作时,JSP Engine 生成 Java 代码来实例化或重用实现自定义标记的类(标记处理程序类)。JSP Engine 也生成 Java 代码来管理标记处理程序的生命周期。清单 2 中的样本代码显示了一个使用六个自定义操作的 JSP 页面;本部分都将引用这一示例。
清单 2.带有自定义操作的样本 JSP 源文件
<%@ taglib uri="utility.tld" prefix="myTags" %>
<BR>
<myTags:repeat iterations="5">
this is tag #1!
</myTags:repeat>
<BR>
<myTags:repeat iterations="6" varName="xyz">
this is tag #2!
</myTags:repeat>
<BR>
<myTags:repeat iterations="2">
this is tag #3!
</myTags:repeat>
<BR>
<myTags:repeat iterations="9" varName="xyz">
this is tag #4!
</myTags:repeat>
<BR>
<myTags:repeat iterations="8" begin="7" >
this is tag #5!
</myTags:repeat>
<BR>
<myTags:repeat iterations="9" begin="6" >
this is tag #6!
</myTags:repeat>
|
标记处理程序重用的约束条件
惟一性
为了让标记处理程序在自定义操作中重用,自定义操作必须是:
- 使用同样的标记处理程序类。
- 具有同样设置的可选属性。
在上面的样本 JSP 中,自定义操作都使用同样的标记处理程序类,
com.yourco.tags.RepeatTag ,它实现了 repeat 自定义操作。然而,自定义操作使用不同的属性设置。定义了 repeat 标记的 TLD(图中没显示)指出 iterations 属性是必须的,但 varName 和 begin 属性是可选的。这表明在样本 JSP 中:
- 标记 1 和 3 可以重用单个标记处理程序。
- 标记 2 和 4 可以重用单个标记处理程序。
- 标记 5 和 6 可以重用单个标记处理程序。
- 标记处理程序的重用不能超越这些标记组。
启用自定义标记处理程序重用可能会使与进行重用的标记功能有关的标记处理程序代码出现问题。为了避免这样的问题,自定义标记处理程序开发人员必须始终遵守这些规定:
- 标记处理程序的 release() 方法必须使它的状态复位并释放它可能已经使用的私有源文件。JSP Engine 确保在标记处理程序被作为垃圾回收之前调用 release() 方法。
- 在 doEndTag() 方法中,所有与实例相关的实例状态必须复位。
keepgenerated
保留生成的 Java 源文件是通过 keepgenerated 参数来配置的:
<jspAttributes xmi:id="JSPAttribute_1" name="keepgenerated" value="true"/>
如果 keepgenerated 配置参数设置为 true,则 JSP Engine 将会保留它生成的 Java 源文件。(以下的代码样本来自于 JSP Engine 生成的 Java 源文件,它被保留了,因为 keepgenerated 设置为 true。)
没有使用标记处理程序池的情况
如果没有使用标记处理程序池,则标记每次启用时都要实例化标记处理程序对象。清单 3 显示了样本 JSP 里为标记 1 和 3 生成的 Java 代码。对于这两个标记,标记处理程序对象
_jspx_th_myTags_repeat_0
和
_jspx_th_myTags_repeat_2
都使用 new 来实例化。样本 JSP 页面的六个标记每个都将有独立的标记处理程序对象,在页面执行完成以后它们都将被部署并作为垃圾回收。图 3 说明在没有使用标记池时标记处理程序的创建。
清单 3.不带标记池的生成的标记处理程序代码
// code generated for tag #1
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_0 = new
com.yourco.tags.RepeatTag();
_jspx_th_myTags_repeat_0.setPageContext(pageContext);
_jspx_th_myTags_repeat_0.setParent(null);
_jspx_th_myTags_repeat_0.setIterations(5);
int _jspx_eval_myTags_repeat_0 = _jspx_th_myTags_repeat_0.doStartTag();
BODY OF ACTION NOT SHOWN
// release() is called on the tag handler because its lifecycle is done
if (_jspx_th_myTags_repeat_0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
_jspx_th_myTags_repeat_0.release();
return;
}
_jspx_th_myTags_repeat_0.release();
.. .. .. .. .. .. .. ..
// code generated for tag #3
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_2 = new
com.yourco.tags.RepeatTag();
_jspx_th_myTags_repeat_2.setPageContext(pageContext);
_jspx_th_myTags_repeat_2.setParent(null);
_jspx_th_myTags_repeat_2.setIterations(2);
int _jspx_eval_myTags_repeat_2 = _jspx_th_myTags_repeat_2.doStartTag();
BODY OF ACTION NOT SHOWN
// release() is called on the tag handler because its lifecycle is done
if (_jspx_th_myTags_repeat_2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
_jspx_th_myTags_repeat_2.release();
return;
}
_jspx_th_myTags_repeat_2.release();
|
图 3. 没有使用标记池时的标记处理程序的创建
使用页面级池的情况
页面级池是通过 usePageTagPool 参数激活的:
<jspAttributes xmi:id="JSPAttribute_1" name="usePageTagPool" value="true"/>
当使用了页面级的标记处理程序池时,标记处理程序的重用可能单独出现在一个页面的标记内,如上面的
标记处理程序重用的约束条件所述。清单 4 显示了在 usePageTagPool 为 true 时,为标记 2 和 4 生成的 Java 代码。对于其他两个标记处理程序(对应于标记 1 和 3,标记 5 和 6)也会生成类似的代码。这样带来的结果就是在 JSP 的执行期间,只创建和部署了三个标记处理程序对象,而不是在没有使用标记池的情况下创建和部署了六个。图 4 展示了使用页面级的标记池时标记处理程序的创建。
在 _jspService 方法(清单 4)中,每个标记处理程序的实例都是在顶部创建,然后在需要的时候使用。由于处理程序的生命周期是在其 _jspService 方法底部的
finally 代码块终止的,所以 release() 方法就是在这一代码块被调用的。页面执行完成以后,这些对象被当作垃圾回收。在对 JSP 页面的单个请求中,一个标记处理程序被多次使用,但它只被创建和部署了一次。
清单
4.带有页面级池的样本标记处理程序代码
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
... ... ... ... ... ... ... ...
// An instance of each tag handler is created
// this handler is used for tags 1 and 3
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_0 = new
com.yourco.tags.RepeatTag();
// this handler is used for tags 2 and 4
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_1 = new
com.yourco.tags.RepeatTag();
// this handler is used for tags 5 and 6
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_2 = new
com.yourco.tags.RepeatTag();
... ... ... ... ... ... ... ...
// Tag handler for tag #2; the handler was created above
_jspx_th_myTags_repeat_1.setPageContext(pageContext);
_jspx_th_myTags_repeat_1.setParent(null);
_jspx_th_myTags_repeat_1.setIterations(6);
_jspx_th_myTags_repeat_1.setVarName("xyz");
_jspx_eval_myTags_repeat_1 = _jspx_th_myTags_repeat_1.doStartTag();
BODY OF ACTION NOT SHOWN
if (_jspx_th_myTags_repeat_1.doEndTag() ==
javax.servlet.jsp.tagext.Tag.SKIP_PAGE){
return;
}
... ... ... ... ... ... ... ...
// Tag handler for tag #4; the same handler used for tag #2 is reused here
_jspx_th_myTags_repeat_1.setPageContext(pageContext);
_jspx_th_myTags_repeat_1.setParent(null);
_jspx_th_myTags_repeat_1.setIterations(9);
_jspx_th_myTags_repeat_1.setVarName("xyz");
_jspx_eval_myTags_repeat_1 = _jspx_th_myTags_repeat_1.doStartTag();
BODY OF ACTION NOT SHOWN
if (_jspx_th_myTags_repeat_1.doEndTag() ==
javax.servlet.jsp.tagext.Tag.SKIP_PAGE){
re
turn;
}
... ... ... ... ... ... ... ...
// Lifecycle of the tag handlers has ended, so release is called()
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
if (_jspx_th_myTags_repeat_0 != null) _jspx_th_myTags_repeat_0.release();
if (_jspx_th_myTags_repeat_1 != null) _jspx_th_myTags_repeat_1.release();
if (_jspx_th_myTags_repeat_2 != null) _jspx_th_myTags_repeat_2.release();
}
}// end of _jspService method
|
图 4. 使用页面级标记池时的标记处理程序的创建
使用线程级池的情况
线程级池是通过 useThreadTagPool 参数激活的:
<jspAttributes xmi:id="JSPAttribute_1" name="useThreadTagPool" value="true"/>
当使用了线程级标记处理程序池时,标记处理程序的重用可能通过单独的请求单独出现在跨单一 Web 模块中的所有 JSP 页面的自定义动作内。清单 5 显示了 useThreadTagPool 为 true 时生成的相关 Java 代码。线程级重用和页面级重用生成的代码的惟一区别在于 _jspService 方法顶部的标记处理程序的初始化以及在其底部的
finally 代码块中生成的代码。图 5 展示了使用线程级别标记池的情况下标记处理程序的创建。
线程池缓存惟一出现的一次标记处理程序,它具有上述的
标记处理程序重用的约束条件中的惟一性。对于在 Web 模块中所有 JSP 内发现的每个惟一性标记,都在遇到标记处理程序时将其缓存在执行 JSP 页面的线程中。
在所有的 Web 模块中,线程都是由 Web 容器分配的,而特定的线程可以跨多个 Web 模块重用。JSP Engine 的标记处理程序池机制保证缓存在特定的 Web 模块中的标记只对该 Web 模块内的 JSP 页面可用,从而避免了出现 ClassCastExceptions 异常(因为标记处理程序对象将由特定的类加载器加载到 Web 容器中)。
(getTagHanler() 中的池机制是通过单个同步代码块实现的,其代码只在新线程第一次遇到时执行,这样就可以将同步对性能的消极影响降到最少。)
清单 5.带有线程级别池的标记处理程序的创建
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
... ... ... ... ... ... ... ...
// An instance of each tag handler is retrieved using the method getTagHandler()
// this handler is used for tags 1 and 3
String _tagKey_myTags_repeat_0 = "com.yourco.tags.RepeatTag";
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_0 =
(com.yourco.tags.RepeatTag)getTagHandler(request, _tagKey_myTags_repeat_0, "com.yourco.tags.RepeatTag");
// this handler is used for tags 2 and 4
String _tagKey_myTags_repeat_1 = "com.yourco.tags.RepeatTag_varName";
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_1 =
(com.yourco.tags.RepeatTag)getTagHandler(request, _tagKey_myTags_repeat_1, "com.yourco.tags.RepeatTag");
// this handler is used for tags 5 and 6
String _tagKey_myTags_repeat_2 = "com.yourco.tags.RepeatTag_begin";
com.yourco.tags.RepeatTag _jspx_th_myTags_repeat_2 =
(com.yourco.tags.RepeatTag)getTagHandler(request, _tagKey_myTags_repeat_2, "com.yourco.tags.RepeatTag");
... ... ... ... ... ... ... ...
// Tag handlers are returned to the pool; release() is called only when the the
// web module is stopped and the tag handler pools for that web module are
// cleared out.
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
putTagHandler(request, _tagKey_myTags_repeat_0, _jspx_th_myTags_repeat_0);
putTagHandler(request, _tagKey_myTags_repeat_1, _jspx_th_myTags_repeat_1);
putTagHandler(request, _tagKey_myTags_repeat_2, _jspx_th_myTags_repeat_2);
}
}
}
|
图 5. 使用线程级别的标记池时的标记处理程序的创建
配置 JSP Engine 来使用 Jikes
Jikes Java 编译器是通过 useJikes 参数激活的:
<jspAttributes xmi:id="JSPAttribute_1" name="useJikes" value="true"/>
当 useJikes 设置为 true 时,JSP Engine 会使用 Jikes Java 编译器来替换来自 JDK 的缺省 javac 编译器。Jikes 是开放源代码编译器,可从
此处获得。WebSphere Application Server Technology for Developers V6.0 并没有附带 Jikes,但 Jikes 在整个 IBM developerWorks 都是支持的。Jikes 版本 1.8 和 1.9 已经在 WebSphere Application Server Technology for Developers V6.0 中用 JSP Engine 进行过测试,并且运行良好。
在转换和编译 JSP 过程中,Jikes 在编译阶段的性能比 JDK 的编译器好。
结束语
可以按照下面三个非常重要的方法来配置 WebSphere Application Server V6 TD 中的 JSP Engine,以便使其更好地适应生产环境和开发环境:
- 在修改 JSP 时重新加载类文件。
- 池化经典自定义标记处理程序对象。
- 使用开放源代码的 Jikes java 编译器。
第 3 部分将会探讨 WebSphere Application Server Technology for Developers V6 中的 JSP Engine 的体系结构,并以此作为这一系列文章的结束。
致谢
作者真诚地感谢 Todd Kaplinger 和 Richard Backhouse 对本文作出的贡献。
参考资料
关于作者  | |  |
Scott Johnson
是 WebSphere Application Server
JSP Engine 的小组负责人。他于 2000 年加入 IBM,在 Research Triangle Park Lab 工作,在此之前的 17
年他曾担任程序员和项目负责人。
|
对本文的评价
|