分享

BEA 实战集锦-探查 Struts 与 WebLogic Server 共用问题

 funronglei 2006-11-18

探查 Struts 与 WebLogic Server 共用问题

问题描述
Struts 是 JAVA 和 J2EE 界最普及、使用最广泛的 MVC 框架之一。自诞生以来,Struts 就以其将业务逻辑与表示逻辑分离的清晰视点给业界留下了深刻印象。本模式将介绍常见错误及解决方法。
 
故障排除
调试 Struts 应用程序时,故障排除可能错综复杂,因为有时错误信息所指示的原因并非错误的真正成因。有时可能甚至不出现任何错误。

请注意,并非下面所有任务都需要完成。有些问题仅通过执行几项任务就可以解决。

快速链接:

任何 Struts 配置的大多数问题都可能是因配置问题所致,多半可能是配置不正确。因此,确保配置没有问题很重要。


更正应用程序文件
Struts 1.1 将许多公用类从 struts.jar 中分离出来。大多数公用功能(如 digestor 实用程序和 Bean 实用程序)已移至公用包中。需要将 commons jar 随 Struts 实现类一起引用。Struts 实现类中已广泛使用 commons 类。

如果不想遭遇那些恼人的 NoClassDefFound 错误,就需要确保 Struts Web 应用程序始终包含下列包。


包名称
用途

commons-beanutils.jar

简单易用的 Java 反射和内省 API 包装器

commons-collections.jar

一组用于扩展和增强 Java Collections Framework 的类

commons-digester.jar

通常用于分析 XML 配置文件的 XML 到 Java 对象映射实用程序

commons-lang.jar

一组公用实用程序类,可以为 java.lang 中的类提供附加功能

commons-logging.jar

各种日志 API 实现的包装器

commons-validator.jar

用于定义 XML 文件中的验证类(验证方法)和验证规则的可扩展框架

jakarta-oro.jar

一组文本处理 Java 类,可以提供兼容 Perl 5 的正则表达式


备注:如果从 Struts 1.0 升级到 Struts 1.1,digestor 类将以单独包的形式位于公用项目下。在 Struts 1.0 中,digestor 类是 Struts 源代码的一部分。

对于任何 Struts 应用程序,类路径中必须有上述类。

返回页首


理解 Struts 配置文件
通过一个基于 XML 的配置文件来记录和控制 Struts 配置。缺省情况下,该文件的名称是 struts-config.xml,位于 Web 应用程序的 WEB-INF 目录中。Struts 有一个中央控制器 Servlet (org.apache.struts.action.ActionServlet),首次加载 Struts 应用程序时,它会对该配置文件进行分析。 

该配置文件包含 Action 类与 Form 类的映射。映射为应用程序提供页面流。因此,配置文件的两个重要部分是 <form-beans><action-mappings>

  • 下面是一个示例 form-bean
    <form-beans>

    <form-bean
    name="LoginForm"

    type="com.test.LoginForm"/>


    </form-beans>
  • 对应的 action-mapping 是这样的:
    <action-mappings>

    <action
    path="/login"
    type="com.test.LoginAction"
    name="LoginForm"
    scope="request"
    validate="true"
    input="/pages/Login.jsp"/>


    </action-mappings>

合并后的应用程序流是这样的:

如果 Struts 配置文件中提供的配置详细信息正确,Struts 控制器会对该应用程序流实施控制。如果提供的路径不正确或未在类加载器中找到 Form Bean 或 Action Bean,控制器将返回运行时错误。

返回页首


Struts Form Bean

那么,准确地讲什么是 Form Bean 呢?Form Bean 是一种 Java Bean,广泛用于映射 HTML 表单与相应的 Java Bean。Form Bean 的编码和使用都很简单。在使用 Form Bean 时,需要密切注意以下几点:

  1. Form Bean 映射到的是 HTML 表单上的元素或控件。例如,如果 HTML 表单包含名为 name 的字段,Form Bean 就会包含名为 name 的属性。

  2. 在映射到 HTML 控件的 Form Bean 中定义的每个属性都必须有与之对应的赋值方法和取值方法。例如,该属性有两个方法:setName()getName()。 

  3. Form Bean 还包含一个名为 validate() 的方法。可以使用 validate 方法验证表单项,如果验证失败,则填充 actionErrors 对象,并将控制权返还给调用页面,随后调用页面会显示这些错误。下一小节将对验证和错误处理做更多介绍。

返回页首

Action

Action 类主要用于处理来自视图的数据和对该数据执行任何业务操作。Action 类是 org.apache.struts.action.Action(其实就是一个 HttpServlet)的扩展。因此实际上是在执行 Servlet。 

这些 action 类与 Servlet 不同,它们不是在 web.xml 中注册,而是映射到 Struts 配置文件中的 action 表单。其类似于以下代码:

<action
path="/login"
type="com.test.LoginAction"
name="LoginForm"
scope="request"
validate="true"
input="/pages/Login.jsp"/>

 

可以使用其中的 path 属性 "/login" 调用 Servlet。

Action 类定义需要先行覆盖,才能执行任何任务的 execute 方法。Execute 方法有权访问对应视图的 actionForm Bean、对整个 Struts 配置的引用、HttpServletRequest 对象及 HttpServletResponse 对象。这使 execute 方法能够对 HttpSession 对象、HttpSelvletRequest 对象HttpServletResponse 对象执行操作。

 

public ActionForward execute(ActionMapping mapping,
                                                        ActionForm form, 
                                                       HttpServletRequest request, 
                                                       HttpServletResponse response)

 

备注:在 Struts 1.0 中,该方法的名称是 perform()。Struts 1.1 已不支持该方法。

Action 类返回 ActionForward 对象。此 ActionForward 对象确定需要将请求发送到的正确视图。还会在 Struts 配置文件中注册需要将控制权转交给的正确视图。 

在上例中,假定在登录失败时需要将控制权传递给 error.jsp,在登录成功时需要将控制权传递给 nextPage.jsp。Forward 标记的注册方式如下:

 

<action
path="/login"
type="com.test.LoginAction"
name="LoginForm"
scope="request"
validate="true"
input="/pages/Login.jsp">
<forward 
    name="failure" 
    path="/error.jsp"/>
<forward 
    name="success" 
    path="/nextPage.jsp"/>
</action>

 

Execute 方法通常以下列语句作为结束语句。

return (mapping.findForward("failure"));

其中的 mapping 指的是 ActionMapping 对象。已定义了特定 action 的 "failure" 路径。因此以上语句实际执行的操作是将请求发送给 error.jsp。  

以上示例中的 <forward> 标记具有局部作用域,可以在定义时所针对的 action 内使用。但也可以定义全局 forward。全局 forward 也在 Struts 配置文件中定义,这与任何其它配置信息是一样的。正如定义全局变量那样,全局 forward 可以在应用程序中的任何地方使用。 


 

<global-forwards>
<forward
name="welcome"
path="/Welcome.jsp"/>
</global-forwards>

 

因此,可以在应用程序中的任何地方使用 mapping.findForward("welcome"),而它始终会将控制权转交给 Welcome.jsp

返回页首


Validate 方法和错误处理
如前所述,可以在 struts-config.xml 中禁用操作和验证。Action 中央控制器将确保不进行验证。 


 

<action
path="/login"
type="com.test.LoginAction"
name="LoginForm"
scope="request"
validate="true"
input="/pages/Login.jsp"/>

 

Validate 方法返回 ActionErrors 对象。这些对象充当错误信息的容器。如果验证失败,将把这些对象返还给调用 JSP,它可以处理对象以显示它们。

返回页首


排除消息资源故障
消息资源帮助开发人员在一个集中位置存储标签、错误信息等内容,简化了后续阶段的维护工作。该集中位置是一个属性文件,存储在应用程序的类路径中,因此组件可以方便地访问。

以下是为 Struts 应用程序定义消息资源的两种方法:

  • web.xml 
  • struts-config.xml

对于 web.xml,将属性文件定义为 ActionServlet 的 param-value。下面是一个简短的示例:


<servlet>
<servlet-name>action</servlet -name>
<servlet-class>
    org.apache.struts.action .ActionServlet
</servlet-class>
<init-param>
<param-name>
    application
</param-name>
<param-value>
   beatest.ApplicationResources
</param-value>
</init-param>
</servlet>

请注意,param-name 应用程序和值表示为beatest.ApplicationResources这表示在应用程序类路径的包 beatest 内一定存在一个名为 ApplicationResources.properties 的属性文件。

在 Struts 1.1 中,可以在 struts-config.xml 中定义资源包。

<message-resources parameter="beatest.ApplicationResources"/>

此处的参数为必需值,它引用类路径 beatest 包中的 ApplicationResources.properties 文件。使用 Struts 1.1 时可以有多个资源包,这使开发人员还能够对资源包进行组织。例如,可以有这样的包:

<message-resources key=”errorBundle”  parameter="beatest.ApplicationErrors"/>

<message-resources key=”labelsBundle”  parameter="beatest.ApplicationLabels"/>

可以在应用程序中对它们进行适当设置。如果用户想要为 HTML 显示标签,则可以使用 labelsBundle

<bean:message bundle="lablesBundle" key="some.message.key"/>

而如果想要显示错误信息,则可以使用 errorBundle。

<bean:message bundle="errorBundle" key="some.error.message"/>

返回页首

使用消息资源时的常见问题
开发 Struts 应用程序过程中的一个常见错误是:

 javax.servlet.jsp.JspException:Missing message for key "<some key name>"

要解决此问题,可以确认是否存在下列情况:

  • 消息不是从正确的资源包取得的。请确保引用的是真正包含所提及的键的正确的资源包。 

  • 资源属性文件不在正确的位置或不在应用程序的类路径中。应用程序资源属性文件应位于 WEB-INF\classes 目录中,或应为 WEB-INF\lib 目录中某个 .jar 文件的一部分。 

  •  使用 null="false" 可避免上述错误。例如:

     <bean:message bundle="lablesBundle" key="some.message.key" null="false">

    这样将会设置一个消息资源包,在文件 MyWebAppResources.properties 的缺省键下提供该资源包。缺少的资源键将显示为“???keyname???”。 

返回页首


排除 Struts 国际化故障
缺省情况下,Struts 在每个用户的会话中提供一个 Locale 对象。可以根据用户提供的信息对此 Locale 对象做适当设置。 

以下是 Struts 国际化检查清单:

  1. 设置了 Locale Servlet 参数。
    确保将 ActionServlet 的 Locale 参数设置为 true。缺省情况下将此参数设置为 true,即缺省情况下启用本地化。

  2. 使用了正确的应用程序资源 Servlet 参数。
    对于 MessageResource,如果指定了正确的语言环境,则 ActionServlet 将在类路径中寻找该语言环境专用的属性文件。例如,如果像下面这样指定 MessageResource: 

    <message-resources parameter="beatest.ApplicationResources"/>

    对语言环境敏感的应用程序将寻找名称为 ApplicationResources_xx_XX.properties 的文件,其中 xx_XX 为特定的语言环境,如 es_USfr_CA

    该属性文件只不过是一个简单的包含一组键值对的文本文件。用户需要确保文件的名称正确并位于类路径中。建议将该文件置于 Web 应用程序的 WEB-INF/classes 目录中。 

  3. 如果用户不在缺省语言环境中,则可以在 ActionServlet 中更改 Locale 对象。可以通过替换会话中的 Locale 对象进行更改。 

    Locale locale = new Locale("English","US");
    session.setAttribute(Action.LOCALE_KEY,locale); 

  4. 如果使用了 Struts 控制器,则可以在 struts-config.xml 中将语言环境指定为控制器声明的一部分。 

    <controller processorClass="org.apache.struts.action.RequestProcessor" debug="2" locale="fr_CA"/>

返回页首


调试和日志记录 Struts 应用程序
WebLogic 提供了它自己的日志子系统,该系统是 WebLogic 的缺省日志框架。不过,也可以将 WebLogic 与其它日志框架(如 Log4j)一起使用。缺省情况下,Struts 将把所有消息记录到 WebLogic 日志框架。要在开发 Struts 应用程序过程中进行最有效的记录日志,需要确保将“Logging Message”严重性设置为“INFO”。


这样一来,将报告所有正常和异常操作,从而可以在出错时进行有效的调试。有关详细信息,请参考 http://e-docs./wls/docs81/ConsoleHelp/logging.html#1055676 (English)。

还建议将所有 system.out.println() 消息都重定向到 WebLogic 日志,以方便调试。可以指定记录这些消息的 stdout 文件。只需编辑 WebLogic Server 脚本,使 JAVA_OPTIONS 变量做以下指定:

-Dweblogic.Stdout="stdout-filename"
-Dweblogic.Stderr="stderr-filename"

有关详细信息,请参考 http://e-docs./wls/docs81/ConsoleHelp/logging.html#1062846 (English)。

要查看所有发出的 HTTP 请求的日志,可以参考 WebLogic Server 生成的访问日志。该日志提供了访问的所有请求连同时间戳和访问的 URL 连同 HTTP 返回代码的详细信息。

例如,访问日志将提供如下信息:

127.0.0.1 - - [13/Jul/2004:21:39:46 -0615] "GET /struts-sample/preregisterCab.do?IndiReport
=true HTTP/1.1" 200 4173 
127.0.0.1 - - [13/Jul/2004:21:41:14 -0615] "POST /struts-sample/getIndiData.do;jsessionid=A05R5lY5jLRJokg8BRMYgLwCOvfuVzC7KEE4AsCZijq
D7l6A22Re!-237055073 HTTP/1.1" 200 4667 
127.0.0.1 - - [16/Jul/2004:00:07:58 -0615] "GET /struts-sample/preregisterCab.do?IndiReport
=true HTTP/1.1" 200 4173 
127.0.0.1 - - [16/Jul/2004:00:08:26 -0615] "POST /struts-sample/getIndiData.do;jsessionid=A32LikMTeXrS5Bnbp7p1TASmcLHkuko9Sudr8Lja
tWw2AqeP6zkt!1759102893 HTTP/1.1" 200 8893 
127.0.0.1 - - [19/Jul/2004:04:39:36 -0615] "GET /struts-sample/preregisterCab.do?IndiReport
=true HTTP/1.1" 200 4173 
127.0.0.1 - - [19/Jul/2004:04:40:16 -0615] "POST /struts-sample/getIndiData.do;jsessionid=A7yxT3KtTy01T7A39DLSup2RPqxvV9uWay325WxB
Lqtj1dlx3Ewa!-431463598 HTTP/1.1" 200 5416 
127.0.0.1 - - [14/Aug/2004:22:36:24 -0615] "GET /struts-sample/preregisterCab.do?IndiRepor
t=true HTTP/1.1" 200 4173 
127.0.0.1 - - [14/Aug/2004:22:36:58 -0615] "POST /struts-sample/getIndiData.do;jsessionid=Be2WKm1nP7DGdX1uIY8PraQdx51wBZTjVSswGHdcbL4njcj
XOdJh!1670519755 HTTP/1.1" 200 4684 
127.0.0.1 - - [14/Aug/2004:22:36:59 -0615] "GET /struts-sample/pages/STFull.jpg HTTP/1.1" 304 0

有关如何控制 HTTP 日志的详细信息,请参考下列链接: 建议的有关 WebLogic 记录功能的阅读材料:

返回页首


Struts 应用程序内的扩展日志记录 

  1. ActionServletweb.xml 中使用调试级别来确保获得扩展的调试消息。有效的 debug 值是 0(不记录)到 6(最严重)。 

  2. 将 detail 参数设置为调试来自 digestor 的消息。以下是 web.xml 的一个片断。

    <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <init-param>
    <param-name>debug</param-name>
    <param-value>4</param-value>
    </init-param>
    <init-param>
    <param-name>detail</param-name>
    <param-value>2</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
    </servlet>
    请注意其中的 debug 和 detail 级别。 

     

  3. 如果使用缺省的 RequestProcesor 控制器,请对附加调试消息使用控制器的 debug 参数。以下是 struts-config.xml 的一个片断。
    <controller processorClass="org.apache.struts.action.RequestProcessor" debug="2"/>

返回页首


调试 WebLogic 类加载器
在开发 Struts 应用程序的过程中,必然会遇到类加载器问题。调试那些 NoClassDefFoundErrorClassNotFoundException 的确是一件麻烦事。 


类加载器和 WebLogic Server 类加载简介

与 Java 的类继承相似,类加载器具有由父类加载器(相当于超类)和子类加载器(相当于子类)构成的层次结构。

启动类加载器是 Java 类加载器层次结构的父级。Java 虚拟机创建此类加载器,然后由它加载 JDK 内部类以及 Java 虚拟机中包括的 java.* 包。例如,java.lang.String 是由启动类加载器加载的。

扩展类加载器是启动类加载器的子级。它加载置于 JDK 的 extensions 目录中的所有 jar 文件。这是一种在不向类路径中添加条目的情况下扩展 JDK 的便捷手段。不过,extensions 目录中的任何内容都必须是独立的。它只能引用 extensions 目录中的类或 JDK 类中的类。JDK 扩展加载器是由系统类路径类加载器扩展而来。大多数 Java 程序员都熟悉这个类加载器。它加载 Java 虚拟机类路径中的类。应用程序特定的类加载器(如 WebLogic Server 创建的类加载器)是系统类路径类加载器的子级。

WebLogic Server 的类加载以应用程序概念为中心。应用程序通常是包含应用程序类的 EAR(企业归档)文件。EAR 文件中的所有内容都将被视为同一应用程序的一部分。较小的应用程序可能是 EJB jar 文件或 Web 应用程序 (WAR) 文件。请注意,如果分别部署 EJB jar 文件和 Web 应用程序 war 文件,则会将它们视为两个应用程序。如果将它们共同部署在一个 EAR 文件内,则将它们视为一个应用程序。每个应用程序均容纳其自身的类加载器层次结构,该结构的父级为系统类路径类加载器。这样就将各应用程序隔离开来,使应用程序 1 无法看到应用程序 2 的类加载器或类。类加载器中没有同级或友元的概念。应用程序类加载器只能看到它们的父类加载器,即系统类路径类加载器。这使 WebLogic Server 可以在同一个 Java 虚拟机内托管多个相互隔离的应用程序。


无法在父类加载器和子类加载器中找到类时,会发生 ClassNotFoundException。这很可能是打包问题造成的。 

加载了请求的类但无法找到依赖类时,会抛出 NoClassDefFoundError。父类加载器中的类从不引用子类加载器中的类。类加载器会先请求它们的父类加载器加载类,然后才会尝试自行加载类,因此在此类情况下可能会遇到 NoClassDefFoundError。  

为调试 WebLogic 类加载器,WebLogic 提供了类加载器特定的调试标志。设置这些调试标志的方法: 

  1. 编辑 StartWeblogic 脚本,添加以下内容作为启动 WebLogic 时的命令行参数。
    Dweblogic.Debug = debug.lineNumbers,debug.methodNames,weblogic.ClassLoaderVerbose,weblogic.ClassLoader

  2. 确保在控制台的“Logging”选项中将“Debug to Stdout”选项设置为“enabled”。
启用这些调试选项后,您就会注意到应用程序寻找的任何类都将有相应的以下日志。
[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag...
With classpath of : ()
Classloader object id (weblogic.utils.classloaders.GenericClassLoader@127f79d finder: weblogic.utils.classloaders.MultiClassFinder@18353cf annotation: )
[GenericClassLoader] : Class org.apache.struts.taglib.html.ImgTag not found.
[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag...
With classpath of : ()
Classloader object id (weblogic.utils.classloaders.GenericClassLoader@17d03c5 fi
nder: weblogic.utils.classloaders.MultiClassFinder@f37a62 annotation: Applicatio
nClassLoader@)
[GenericClassLoader] : Class org.apache.struts.taglib.html.ImgTag not found.
[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag...
With classpath of : (C:\APP-INF\classes)
Classloader object id (weblogic.utils.classloaders.GenericClassLoader@17447c5 finder: weblogic.utils.classloaders.MultiClassFinder@e7eec9 annotation: struts-example@)
[GenericClassLoader] : Class org.apache.struts.taglib.html.ImgTag not found.
[ChangeAwareClassLoader] : weblogic.utils.classloaders.ChangeAwareClassLoader@165d0e0 finder: weblogic.utils.classloaders.MultiClassFinder@edd9de annotation: struts-example@struts-example about to loadClass(org.apache.struts.taglib.html.Img
Tag)
[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag..
.
With classpath of : (C:\bea-plat-81sp3\user_projects\domains\sqlservdomain\myserver\.wlnotdelete\extract\myserver_struts-example_struts-example\jarfiles\WEB-INF
\lib\log4j.jar;C:\bea-plat-81sp3\user_projects\domains\sqlservdomain\myserver\.w
lnotdelete\extract\myserver_struts-example_struts-example\jarfiles\WEB-INF\lib\log4j-core.jar)
Classloader object id (weblogic.utils.classloaders.ChangeAwareClassLoader@165d0e0 finder: weblogic.utils.classloaders.MultiClassFinder@edd9de annotation: struts-example@struts-example)
[GenericClassLoader] : Found class: org.apache.struts.taglib.html.ImgTag
[GenericClassLoader] : weblogic.utils.classloaders.ChangeAwareClassLoader@165d0e0 finder: weblogic.utils.classloaders.MultiClassFinder@edd9de annotation: struts-example@struts-example defined class class org.apache.struts.taglib.html.ImgTag

请注意,上例中 Struts 应用程序寻找的是 org.apache.struts.taglib.html.ImgTag 类。首先在父类加载器中寻找该类,然后在应用程序加载器中寻找,最后在 war 类加载器中寻找。

返回页首

如果在类加载器中找不到某个类,您会注意到日志中产生了下面这样的消息。

[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag...
With classpath of : ()
Classloader object id (weblogic.utils.classloaders.GenericClassLoader@10d3f0d finder: weblogic.utils.classloaders.MultiClassFinder@1510d96 annotation: )
[GenericClassLoader] : Class org.apache.struts.taglib.html.ImgTag not found.
[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag...
With classpath of : ()
Classloader object id (weblogic.utils.classloaders.GenericClassLoader@1ce64f6 finder: weblogic.utils.classloaders.MultiClassFinder@52fecf annotation: ApplicationClassLoader@)
[GenericClassLoader] : Class org.apache.struts.taglib.html.ImgTag not found.
[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag...
With classpath of : (C:\APP-INF\classes)
Classloader object id (weblogic.utils.classloaders.GenericClassLoader@1d6d61d finder: weblogic.utils.classloaders.MultiClassFinder@d6ee28 annotation: struts-example@)
[GenericClassLoader] : Class org.apache.struts.taglib.html.ImgTag not found.
[ChangeAwareClassLoader] : weblogic.utils.classloaders.ChangeAwareClassLoader@18a6890 finder: weblogic.utils.classloaders.MultiClassFinder@ad8bb4 annotation: struts-example@struts-example about to loadClass(org.apache.struts.taglib.html.ImgTag)
[GenericClassLoader] : Looking for class: org.apache.struts.taglib.html.ImgTag...
With classpath of : (C:\bea-plat-81sp3\user_projects\domains\sqlservdomain\myserver\.wlnotdelete\extract\myserver_struts-example_struts-example\jarfiles\WEB-INF
\lib\log4j.jar;C:\bea-plat-81sp3\user_projects\domains\sqlservdomain\myserver\.w
 

lnotdelete\extract\myserver_struts-example_struts-example\jarfiles\WEB-INF\lib\log4j-core.jar)
Classloader object id (weblogic.utils.classloaders.ChangeAwareClassLoader@18a689
0 finder: weblogic.utils.classloaders.MultiClassFinder@ad8bb4 annotation: struts
-example@struts-example)
[GenericClassLoader] : Class org.apache.struts.taglib.html.ImgTag not found.
<Nov 17, 2004 4:37:52 PM PST> <Error> <HTTP> <BEA-101017> <[ServletContext(id=28746180,name=struts-example,context-path=/struts-example)] Root cause of ServletException.
java.lang.NoClassDefFoundError: org/apache/struts/taglib/html/ImgTag
at jsp_servlet.__index._jspService(__index.java:434)
at weblogic.servlet.jsp.JspBase.service(JspBase.java:33)
at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run(ServletStubImpl.java:996)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:419)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:463)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:315)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run
(WebAppServletContext.java:6452)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:118)
at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:3661)
at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2630)
at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:219)
at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:178)

请注意,在所有可能的类加载器中搜索类未果后,发生了 NoClassDefFoundError 错误。 

如果将 EJB 与 Struts 应用程序一起使用,则应使用 Ear(企业归档)格式打包应用程序。虽然可以分别部署 WAR 和 JAR 文件,但如果将它们共同部署在一个 EAR 文件中,则所形成的类加载器排布将使 Servlet 和 JSP 能够找到 EJB 类。

类加载器结构是这样的:


请注意,EJB 类加载器现在是 Web 应用程序的父类加载器。

返回页首

如果 EJB 和 Web 应用程序使用公用类,将遇到以下两种可能的情况:

  1. 需要维护重复类
  2. 使用 manifest 文件提供不同类加载器间共享类的类路径

WebLogic 8.1 推出了为“Enterprise Archive”使用 APP-INF 这一方案来解决上述问题。将实用程序 JAR 文件置于 APP-INF/lib 目录中,将各个类置于 APP-INF/classes 目录中。将把这些类加载到应用程序的根类加载器中,从而使 Struts 应用程序和 EJB 都能够访问。  

备注:只有 WebLogic 8.1 和以上版本中才提供 APP-INF 功能。对于 WebLogic 8.1 之前的版本,建议的方法是使用表明文件选项。

有关类加载器在 WebLogic Server 中的工作方式的详细说明,请参考下列链接:

  1. WebLogic Server Appliation Classloading (English)
  2. JAR File Specification

返回页首


Struts 应用程序性能问题

  • 为对象使用适当的作用域
    避免使 HttpSession 膨胀,而应评估在请求中存储对象这一方案的可行性。可以将不需要长时间持久存储的对象作为 HttpSessionRequest 的一部分来存储,这些对象用后即会被销毁。作为一项惯例,应将 JSP 中 useBean 标记的作用域最小化。因此,Action 表单的子类不应具有会话或应用程序的作用域,除非已无其它方案可供选择。 

  • gif 和 jpeg 数量过多
    站在用户的角度看,其浏览器中页面显示的响应时间取决于下载速度和页面的复杂性。例如,图形的数量。即使各单项 Web 内容的下载都相当快,设计不佳的图形极多的动态网站也会让人有“慢”的感觉。 

  • 预编译 JSP
    预编译 JSP 可以为首次访问 Struts 应用程序的用户提供更好的性能。请使用 weblogic.appc(WLS 8.1 及更高版本)或 weblogic.jspc 来预编译应用程序。 

  • 刷新静态页面
    如果只修改了静态文件,则可以刷新它们而不用重新部署整个应用程序。请使用 weblogic.deployer 实用程序来完成此任务。请参考
    http://e-docs./wls/docs81/webapp/deployment.html (English)

  • 标记库过多
    实际上,Struts 框架本身就使用了大量标记库。除非不得已,建议在任何情况下都要最充分地利用这些现成的库,而不要创建新库。自定义标记会产生性能开销。请尽可能少用。

  • 使用 Servlet 过滤器
    这可能会成为性能开销。请确认它是否为应用程序可接受的开销。 

  • 充分调整 JVM
    请确保充分调整 JVM。有关如何调整 JVM 的更多详细信息,请参考 http://e-docs./wls/docs81/perform/JVMTuning.html (English)。 

  • 将 EJB 与 Struts Web 应用程序打包在一起
    避免在 WebLogic Server 上将 EJB 档案与 Web 应用程序作为独立的、彼此无关的应用程序进行部署。如果客户端在同一企业应用程序内,WebLogic Server 会优化 EJB 访问。

返回页首

Struts 最佳实践

  1. 始终依据 JSP 规范定义缺省错误页面。这样如果在处理 Struts 页面过程中出错,将显示错误页面而不是无任何内容的空白屏幕。在 WebLogic 中,可以通过引用 http://e-docs./wls/docs81/webapp/web_xml.html#1017571 (English) 处的链接来设置错误页面。

  2. 使用 ExceptionHandler 来处理异常。可以在 Struts-config 文件中声明 ExceptionHandler。可以将控制权传递给相应的错误处理程序页面。可以在需要将控制权传递给非标准错误页面时使用它。 

  3. 将 EJB 与 Struts 一起使用时,使用 Facade 模型调用 EJB。避免直接调用实体。避免将句柄缓存到无状态会话 Bean 中。

  4. 建议不使用 Struts 数据源,而应在进行任何数据库相关操作时使用 WebLogic 数据源,以利用 WebLogic 提供的连接池和事务控制功能。

  5. 仍处于开发阶段时,使用展开 war 格式部署应用程序以节省开发时间。应以开发模式启动 WebLogic Server,以利用 WebLogic 提供的热部署功能。

  6. 如果使用 EJB 和 Struts 应用程序间共享的实用程序类简化对实用程序类和实用程序档案的打包,则请使用 WebLogic 8.1 提供的 APP-INF 功能。

  7. 不将应用程序类添加到服务器的类路径中。服务器处于运行状态时,将无法更改服务器类路径中的任何内容。

返回页首


WebLogic Server 已知问题
您可以定期查看所用 WLS 版本的“Release Notes”,了解 Service Pack 中的“Known Issues”或“Resolved Issues”的详细信息及浏览 Weblogic Server 与 Struts 共用时的问题。方便起见,下面提供了这些发行说明的链接:

对于需要特别注意之处,请参阅以下 CR,在相应版本 Service Pack 的发行说明中注明了已有针对它们的解决方法: 

  • CR109391 - 将不可序列化的对象置于 ServletContext 中时,WebLogic Server 甚至尝试也要将它们反序列化,结果导致 NotSerializableException。在 Welogic 7.0 SP5 (English) 中,此问题已得到解决。
  • CR134412 - 没有为错误页面正确设置类加载器和环境上下文。在 WLS 8.1 SP3 (English) 中,此问题已得到解决。 
  • CR175651 - 问题成因是,在取消部署或重新部署 Web 应用程序过程中,容器不等待进行中的 webapp 请求完成。由此引发的问题是,如果某个 Web 应用程序依赖使用该上下文,取消部署后就会发生 NPE,因为该上下文已不再有效。在 WebLogic 8.1 SP4 (English) 中,此问题已得到解决。
使用搜索功能也可以搜索到“Release Notes”,还可以搜索到其它支持解决办法及与 CR 有关的信息,如需要更多帮助?中所提到的内容。如果客户签订了技术支持合同,则可以登录 http://support./,登录后会看到为 Solutions 和 Bug Central 提供的 Browse portlet,可在其中按产品版本浏览最新提供的 CR。

返回页首


外部资源

返回页首


需要更多帮助?
如果您已经理解这个模式,但仍需要更多帮助,您可以:
  1. http://support. 上查询 AskBEA(例如,使用“investigating struts with weblogic server”),以查找其它已发布的解决办法。技术支持合同客户:确保已经登录,可以访问提供的与 CR 有关的信息。
  2. http://newsgroups. 上,向 BEA 的某个新闻组提出更详细具体的问题。

如果这还不能解决您的问题,并且您拥有有效的技术支持合同,您可以通过登录以下网站来打开支持案例:http://support.


反馈

请给我们提供您的意见,说明此支持诊断模式“探查 Struts 与 WebLogic Server 共用问题模式”一文是否有所帮助、您需要的任何解释,以及对支持诊断模式的新主题的任何要求。


免责声明

依据 BEA 与您签署的维护和支持协议条款,BEA Systems, Inc. 在本网站上提供技术技巧和补丁供您使用。虽然您可以将这些信息和代码与您获得 BEA 授权的软件一起使用,但 BEA 并不对所提供的技术技巧和补丁做任何形式的担保,无论是明确的还是隐含的。

本文档中引用的任何商标是其各自所有者的财产。有关完整的商标信息,请参考您的产品手册。

返回页首

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多