IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere  >

IBM WebSphere 开发者技术期刊: WebSphere Application Server V6 中的 JavaServer Pages -- 第 3 部分

JSP 引擎的体系结构

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Scott Johnson (scottjoh@us.ibm.com), 项目负责人, IBM
Richard Backhouse (backhous@us.ibm.com), 首席架构师, IBM

2004 年 12 月 01 日

本文是本系列文章(分三部分)的结束部分,描述了 WebSphere® Application Server V6 中 JSP 引擎的体系结构,经过较大程度地修改,它可以支持 JSP 2.0 规范的要求,并且提高了它的性能和可配置性。

引言

关于 WebSphere Application Server V6 中的 JavaServer Pages (JSP) 文章系列的第 1 部分描述了内部操作、配置参数以及新的批处理编译器的处理过程。第 2 部分详细讨论了 JSP 引擎可用性的性能调优选项,并显示了如何用预部署的应用程序来简化部署过程并提高运行时性能。最后,在第 3 部分中,我们将研究新 JSP 引擎的体系结构。

但是,本文首先研究了扩展 JSP 2.0 规范的几个方面,这些方面都优于先前的规范。WebSphere Application Server V6 中的 JSP 引擎支持 JavaServer Pages 2.0 规范,该规范于 2003 年 11 月最终定稿。JSP 2.0 规范通过增加以下几条,在几个重要的方面扩展了先前的 1.2 规范:

  • 用于从 JSP 页面访问数据的表示语言,最先是为 JSTL 1.0 开发的,现在已合并到 JSP 2.0 规范中了。
  • 新型自定义标签 API,Simple Tag Extension API,它与经典标签处理程序相比,生命周期不是那么复杂,更容易合作,而且使得标记处理程序既可以用 JSP 语法又可以用 Java™ 语法来编写。
  • JSP 片段,是 JSP 页面的一部分,标记处理程序能用它来产生定制的内容。
  • 改进的用于 JSP 的 XML 语法作为 XML 文档传递。

WebSphere Application Server V6 JSP 容器经过较大程度地修改可以支持 JSP 2.0 规范的要求,并且提高了它的性能和可配置性。(在本文中,术语 JSP 引擎和 JSP 容器将交换使用。)最重要的变动包括:

  • 提出新的转换构架。
  • 运行时与 WebSphere Application Server V6 Web 容器更紧密的集成。
  • 控制 JSP 类的类加载的新选项。

上面的各项将在下面的章节中进行讨论。





回页首


JSP 容器的任务

我们从对 WebSphere Application Server 中 JSP 容器的任务概述开始,帮助为讨论 JSP 容器的体系结构做好准备。在 WebSphere Application Server 中,我们对 Web 容器和 JSP 引擎进行了区分,它们的任务是不同的。通常,我们找出的区别是:JSP 引擎了解处理 JSP 资源的所有事情,而 Web 容器了解处理 servlet 的每件事情但却几乎不知道有关 JSP 资源的事情。

JSP 2.0 规范没有对 JSP 容器和 Web 容器进行区别。事实上,规范上写着:

"JSP 容器是系统级的实体,能为 JSP 页面和 servlet 组件提供生命周期管理和运行时支持。发送到 JSP 页面的请求由 JSP 容器传送到适当的 JSP 页面执行对象。术语 Web 容器和 JSP 容器是同义的。"

在 WebSphere Application Server 中,大部分 JSP 规范要求由 JSP 引擎提供,然而有一些由 Web 容器提供。表 1 列出了 JSP 容器的任务,以及 WebSphere Application Server V6 中这些任务的实现者。

表 1 . JSP 容器的任务

JSP 容器的任务 Websphere Application Server V6 中的实现者
验证 JSP 页面和文档的语法,将有效的 JSP 页面和文档转换为 Java 代码并且编译成 sevlet 类 (JSP 页面执行类)。完全由 JSP 容器实现。
对于 JSP 资源的运行时请求处理:
  • 实例化/类加载 JSP 页面执行 sevlet。
启用 JSP 运行时编译和重新加载时,JSP 容器将为请求的 JSP 页面创建自定义类加载器。这个自定义类加载器在运行时重新加载 JSP 页面。

Web 容器 在某些配置场景下将使用 context 类加载器,而不使用 JSP 类加载器:
  1. 禁用了 JSP 运行时编译和重新加载,JSP 类是利用全包名称生成时。
  2. web.xml 中利用 <servlet-class> 标签代替 <jsp-file> 标签将 JSP 页面配置为 servlet 时。
在所有的实例中,JSP 容器都无法调用实例化和类加载流程,这是由于 Web 容器(通过 ServletWrapper 类)负责实际的 JSP 页面实现类的实例化和类加载。
JSP 资源的运行时请求处理:
  • 将请求传递给适当的 JSP 页面实现 sevlet。
完全由 Web 容器实现。
JSP 页面 sevlet 的生命周期的管理,包括调用初始化、破坏方法和其他特定于容器的方法。 完全由 Web 容器实现。
需要的时候再次生成和再次实例化 JSP 页面实现类(例如,修改 JSP 或者它的依赖性时)。完全由 JSP 容器实现。
为 JSP 类提供运行时支持。完全由 JSP 容器实现。
为 JSP 资源的预编译提供支持。完全由 JSP 容器实现。
按照 JSR-045 提供调试支持(其它语言的调试支持)。完全由 JSP 容器实现。





回页首


JSP 容器的转换框架

该转换构架管理 W3C 文档对象模型 (Document Object Model,DOM) 对象的处理,该对象是由 JSP 容器从 JSP 页面或 JSP 容器创建的。该框架提供了一个结构,在这个结构中将 Java 类配置成能处理或“访问” DOM 对象的元素,然后再对它们进行操作。

这些访问类的典型操作是:

  • 验证 JSP 语法的正确性,并且报告所有的验证错误。包括文件、自定义标签、JSP 指示和标准操作等等都需要验证。
  • 扫描正被转换的 JSP 使用的标签文件,这样可以在生成标签文件类自身前生成由 JSP 确定和使用生成的类信息(例如,TagFileInfo)。
  • 如果启用了调试,生成用于 JSP 的源图 (SMAP),并将其嵌入到生成的类中。
  • 生成用于 JSP 的 Java 类和它可能用到的标签文件。如果确认处理过程没有错误,生成用于 JSP 页面和任何所包括的标记文件的 Java 源代码。
  • 编译 Java 类和报告所有的错误。用 javac 处理所包括的 JSP 时编译标记文件源代码。

由 XML 文件配置转换构架。这个配置文件:

  • 将单个的访问类与任务或离散操作联系起来。例如,类 ValidateJspVisitor 可能与任务 JspValidate 联系起来。
  • 将访问类合并到执行系列操作的集合中。例如,集合 DebugJspTranslation 可能由下面的访问类任务组成:
    • TagFileDependencyCheck
    • JspValidate
    • JspGenerate
    • Smap。

JSP 需要处理时,JSP 容器创建一个 JspTranslatorFactory 类实例并将所希望访问类集合的名字传递给它。工厂返回 JspTranslator 类的实例,该实例是配置用来执行集合所定义的任务的。

例如,DebugJspTranslation 集合所配置的 JspTranslator 将执行 JSP 和标签文件验证、Java 源代码的生成,接着是生成满足 JSR-045 要求的 SMAP 用于源级 JSP 调试。访问类集合 JspTranslation 若去掉 Smap 任务可能与 DebugJspTranslation 集合相同。

访问者类有定义良好的机制方便彼此间的通信。例如,TagFileDepenencyCheck 访问者可能移植一个复杂的对象,它可以确定在验证标记文件过程中发现的标记文件的所有属性。这个对象将传送给后来的 JSP 访问者类,该 JSP 访问者类将在 JSP 验证和生成 Java 源代码的过程中使用这个对象。

JSP 转换构架的可配置性使得 JSP 容器在响应新的请求时可以更快地被修改。这些请求可能来自将来的 JSP 规范,或者其它地方。例如,为增强 Java 源代码的生成,可以编写定制访问者类集合来搜集最优化数据。这些新类将与任务联系在一起,并将那个新任务添加到访问者集合中。利用访问者类通讯机制,最优化数据将被传送给现有的访问者类,这些类生成 Java 源代码,并经过修改后使用这个信息。

JSP 转换构架的配置对客户 Web 应用程序是不公开的,客户 Web 应用程序的需求由支持 JSP 2.0 规范的标准配置满足。





回页首


JSP 容器的运行时任务

在先前的 WebSphere Application Server 版本中,JSP 容器的运行时处理器是作为网关 servlet 实现的。例如,在 WebSphere Application Server V5 中,由类 JspServlet 实现的网关 servlet,通过 Web 容器实例化,并通过对 JSP 扩展的资源处理请求进行配置。Web 容器接收到 JSP 请求时,请求被分派给 JspServlet,而 JspServlet 又依次将请求传送到恰当的 JSP 中。JspServlet 不仅必须实现 JSP 特定的功能,还必须复制 Web 容器的功能,例如:

  • 管理 JSP 类的生命周期,从初始化到破坏。
  • 设置性能监控基础设施 (Performance Monitoring Infrastructure,PMI) 挂钩。
  • 设置 servlet 生命周期监听器挂钩。
  • 网关 servlet 自身是一个容器,因为它将所有的引用存储到它所加载的 JSP 中。

在 WebSphere Application Server V6 中,不再使用 JspServlet 网关 servlet。不再在 JSP 和 Web 容器间复制功能。另外,Web 容器收到 JSP 请求和 JSP 页面实现 servlet 返回响应这段时间内可以缩短路径。

WebSphere Application Server V6 采用" Web 扩展处理器"体系结构,在这个结构中,JSP 扩展处理器取代了 JspSever 网关 servlet。Web 容器为它所加载的每个 Web 模块实例化一个 JSP 扩展处理器。JSP 扩展处理器依次对每个请求的 JSP 生成一个 servlet 封装器对象。JSP 扩展处理器和 JSP servlet 封装器负责执行表 2 中的操作。(如果利用 <servlet-class> 标签在 web.xml 中将 JSP 配置为 servlet,那么在请求那个 JSP 的过程中从来不会调用 JSP 扩展处理器。)

表 2. JSP 扩展处理器和 JSP servlet 封装器采取的操作

出现这种情况时 JSP 扩展处理器这样处理: JSP servlet 封装器这样处理:
Web 容器收到对 JSP 的第一个请求,并将其传递到 JSP 扩展处理器。JSP 扩展处理器为请求的 JSP 创建 JSP servlet 封装器,然后将封装器返回给 Web 容器。Web 坚持使用这个封装器并用针对那个 JSP 请求的 URI 与它联系。处理对 JSP 的第一个请求时,JSP servlet 封装器可能需要:
  • 创建 JSP 页面的执行 servlet,包括对 JSP 源代码的验证、转换和编译。
  • 通过封装器的父类 ServletWrapper 实例化和类加载那个 servlet。

JSP 容器的配置选项能改变这个行为。(参阅 JSP 类加载。)
对 JSP 的第二个及所有后来的请求都由 Web 容器接收。不调用 JSP 扩展处理器。为了查看由于修改 JSP 是否需要再次转换,JSP servlet 封装器由 Web 容器直接调用。
根据 JSP 容器的配置,JSP servlet 封装器将再次转换 JSP,并按照需要创建新的页面实现 servlet。
无论如何,封装器将调用它的父类 ServletWrapper,为了提供服务它将这个请求传递给页面实现 servlet。

图 1 描述了 Web 容器和 JSP 扩展处理器间关系的高级视图。


图 1. 为每个 Web 模块指定一个唯一的 JSP 扩展处理器
图 1. 为每个 Web 模块指定一个唯一的 JSP 扩展处理器

JSP 扩展处理器是 Web 容器的可插入组件。在 WebSphere Application Server V6 中,JSP 扩展处理器仅仅是几种扩展处理器中的一种。

扩展处理器由扩展处理器工厂实例化。例如,Web 模块的 JSP 扩展处理器由全球 JSP 扩展处理器工厂实例化。启动 Web 容器时,扩展工厂用应用服务器的 Web 容器来注册自身。

一旦 Web 容器已经启动,它就拥有一个所有注册了的扩展工厂列表。Web 容器加载独立的 Web 模块时,遍历这列可用的扩展处理器工厂。扩展处理器工厂返回一个扩展处理器实例,然后该实例与一个或多个 URL 模式相关联,这些模式将在那个特殊的 Web 模块中得到处理。这些 URL 模式是由扩展处理器和它的工厂提供的。工厂提供标准的扩展名,扩展处理器提供它将服务的特定于 Web 模块的扩展名。注意在任何两个所给定的 Web 模块中不同的配置选项都可能导致扩展处理器在每个 Web 模块中处理不同的 URL 模式,或者甚至能导致处理器加载到一个 Web 模块中而不是加载到另一个模块中。

图 2 到 4 描述了 JSP 扩展处理器的创建和它在请求处理中的任务。


图 2. 启动 Web 容器时注册 JSP 扩展工厂
图 2. 启动 Web 容器时注册 JSP 扩展工厂

图 3. 加载 Web 模块时实例化 JSP 扩展处理器
图 3. 加载 Web 模块时实例化 JSP 扩展处理器

图 4. 在处理请求过程中实例化 Servlet 封装器
图 4. 在处理请求过程中实例化 Servlet 封装器




回页首


JSP 类加载

  1. 如何加载 JSP 类

    通过 JSP 引擎的类加载或者 Web 模块的类加载,可配置加载一个 JSP 类。

    默认情况下,用 JSP 引擎的类加载器实例来加载 JSP 类,这样当修改 JSP 源或者它的任意一个依赖性时,可以启用运行时 JSP 类的重新加载。默认情况下,由 JSP 引擎的类加载器的唯一的实例加载各 JSP。这使得在必要时可重新加载单独的 JSP 类,而不会影响到任何其它加载的 JSP 类。

    在下面的任何场景中,JSP 类都将由 Web 模块的类加载器来加载:

    1. 将 JSP 引擎配置参数 useFullPackageNames 设置为 true ,并且在 web.xml 中利用表 2 中的场景 <servlet-class> 将 JSP 配置为 servlet。
    2. 将 JSP 引擎配置参数 useFullPackageNamesdisableJspRuntimeCompilation 两项都设为 true。在这种情况下,无需将 JSP 配置为 web.xml 中的 servlet。

  2. 将 JSP 配置为 servlet

    可以将 JSP 配置为 web.xml 中的 servlet。有两种方法可以实现这一点,如同下表 3 中所描述的那样。但是在将 JSP 配置为 servlet 之前,需考虑以下内容:

    • 重新加载能力
      如果运行的时候需要重新加载 JSP,对 JSP 的请求必须由 JSP 引擎处理。表 3 中的 <servlet-class> 场景将禁用运行时 JSP 的重新加载,然而 <jsp-file> 场景将与重新加载是兼容的。

    • 减少类加载器的数目
      如果运行的时候不需要重新加载修改过的 JSP,而且又想得到限制类加载器实例的数目,那么可以使用表 3 中的 <servlet-class> 场景。类似的,不需要将 JSP 配置为 servlet 就可以使用前面章节中的场景 B。

    表 3. 将 JSP 配置为 servlet

    场景 实例 与运行时重新加载兼容? 使用了多个类加载器? useFullPackageNames
    <jsp-file> <servlet>
    <servlet-name>jspOne</servlet-name>
    <jsp-file>jspOne.jsp</jsp-file>
    </servlet>
    YesYes可以为 true 或者 false
    <servlet-class> <servlet>
    <servlet-name>jspTwo</servlet-name>
    <servlet-class>_ibmjsp.jspTwo</servlet-class>
    </servlet>
    NoNo必须为 true

    JSP 批处理编译器工具帮助将 JSP 配置为 servlet。useFullNames 为 true 时,JSP 批处理编译器为每个成功转换和编译的 JSP 生成 <servlet><servlet-mapping> 元素。这些元素被写到一个名为 generated_web.xmlweb.xml 碎片文件中,它位于由 JSP 批处理编译器处理过的 Web 模块二进制 WEB-INF 目录下(这个目录位于部署的应用程序的 EAR 文件中)。为了将 JSP 配置为 servlet 可复制粘贴所有或部分这些元素到 WEB-INF 文件中。

    知道应用服务器正在使用的 web.xml 的位置是很重要的。在 WebSphere Application Server V6 中,可从应用程序二进制(应用程序的 EAR 文件)或者配置存储库进行特定于应用程序的配置。如果应用程序部署在 WebSphere Application Server 中,并且将 Use Binary Configuration 标志设置为 true,那么在在 Web 模块的二进制目录中查找 WEB-INF/web.xml 文件,而不是在配置存储库中查找:

    • 配置存储库目录的实例:
      {WAS_ROOT}/profiles/profilename/config/cells/cellname/applications/
      enterpriseappname/deployments/deployedname/webmodulename


    • 应用程序二进制目录的实例:
      {WAS_ROOT}/profiles/profilename/installedApps/nodename/
      EnterpriseAppName/WebModuleName/

    如果在预部署应用程序中执行 JSP 批处理编译器,那么 web.xml 文件在 Web 模块的 WEB-INF 的目录中。

  3. 所生成文件的包和目录

    默认情况下,生成带包语句的用于所有 JSP 的 .java 文件:

    package com.ibm._jsp;

    JSP 引擎的类加载器知道当所有的 JSP 类都在同一个包中时该如何加载它们。.java 文件自身位于 JSP 源镜像目录结构内的文件系统中。如果 JSP 引擎配置参数useFullNames 设置成 true,可生成带包语句的 .java文件:

    package _ibmjsp.<JSP 所在的目录结构>;

    web.xml 中使用全包名称将 JSP 配置为 servlet。

    表 4. 用于生成的 .java 和 .class 文件的包和目录结构实例

    JSP 文件 Java 包 文件系统中 .java/.class 文件的位置
    Default FullNames=true Default useFullNames=true
    /myJsp.jsp com.ibm._jsp _ibmjsp / /_ibmjsp
    /jspFiles/jspOne.jsp com.ibm._jsp _ibmjsp.jspFiles /jspFiles /_ibmjsp/jspFiles
    /dir with spaces/jspTwo.jsp com.ibm._jsp _ibmjsp.dir_20_with_20_spaces /dir with spaces /_ibmjsp/dir_20_with_20_spaces





回页首


结束语

WebSphere Application Server V6 中的 JSP 引擎从以前的版本中提出了三个主要的变化:

  • 可配置的转换框架使 JSP 容器能更快的修改以响应新的要求,例如 JSP 规范变化和今后的增强。
  • Web 扩展处理器框架通过消除 JspServlet 网关 servlet 使响应时间更快。
  • 新的类加载选项使客户在开发和生产服务器环境中为获得最佳性能配置 JSP 引擎。





回页首


致谢

作者感谢 Arvind Srinivasan、Todd Kaplinger、Kevin Vaughan 和 Srinivas Hasti 对本文的贡献。

专利申请的注释
JSP 容器的转换框架和 Web 容器的扩展处理器框架均是由 IBM 提出的 U.S.专利申请的主题。



参考资料

  • 有关 WebSphere Application Server 的详细信息,请访问 developerWorks WebSphere Application Server 专区。在那里,您会发现很多技术文档、入门文章、培训、下载、产品信息、技术支持参考资料以及更多。

  • Developer Bookstore。成百上千的针对开发人员的技术书籍以 35% 的折扣零售。

  • WebSphere 论坛。特定于产品的论坛,在这里您可以咨询问题,并且可以与其它的 WebSpher 用户互相交流。

  • developerWorks blogs。正在开设软件专家专栏,用户可以发表自己的评论。


作者简介

Scott Johnson 是 WebSphere Application Server JSP 处理器团队的负责人和合作体系架构师。他于 2000 年加入 IBM,在 Research Triangle Park Lab 工作,在此之前的 17 年他曾担任程序员和项目负责人。Scott 是 IBM 的 JSR 245,JavaServer Pages 2.1 专家组的代表。


Richard Backhouse 是 WebSphere Application Server JSP 处理器的首席架构师。他已经做了 20 年的软件开发。Richard 是 IBM 的 JSR 252,JavaServer Faces 1.2 专家组的代表。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款